home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-02-12 | 156.4 KB | 5,119 lines |
- /****** intoids.library/--background-- **************************************
- *
- * NAME
- * intoids.library -- Arbitrary precision integer math in 32 bits.
- *
- * FUNCTION
- * This set of subroutines lets other programs easily handle large
- * integer numbers. It is a wrapper around the GNU Integer library
- * (which implements large integers as an array of shorts) that lets you
- * deal with all integers as 32 bit values (small integers are stored as
- * a shifted odd value and larger ones are stored as a pointer to a
- * variation of the GNU large integer). It also supports special values
- * for infinity and not-a-number conditions. Written to support large
- * sized files in the upcoming AGMS virtual file system.
- *
- * INPUTS
- * RecycleMe - most functions that return an Intoid also take a
- * parameter called RecycleMe. Treat it as if it is used in a call
- * to the FreeIntoid function. If RecycleMe isn't NULL then its
- * storage will be recycled to hold the result (or reallocated if it
- * is too small). If RecycleMe is NULL then new memory will be
- * allocated for the function result. If the function fails
- * (returns NULL) then the RecycleMe variable is deallocated. This
- * is here mostly to reduce the number of memory allocations that
- * would otherwise be made.
- *
- * RESULT
- * Intoid values - all functions returning Intoids will return NULL if
- * out of memory or if the number is too big to be represented.
- * Some also return NULL for not-a-number error conditions (like
- * divide by zero).
- *
- * COPYRIGHT
- * Modifications for storing smaller integers in 32 bit values and
- * conversion to an Amiga library copyright (C) 1996 by Alexander G. M.
- * Smith. Original long integer code copyright (C) 1988 Free Software
- * Foundation.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * AUTHOR
- * Modifications for the Amiga library and 32 bit storage implemented by
- * Alexander G. M. Smith, Ottawa Canada, agmsmith@achilles.net,
- * agmsmith@FreeNet.Carleton.ca, agmsmith@bix.com,
- * 71330.3173@compuserve.com, and probably other places in the future.
- * Send mail to all these addresses to find ones which are still valid
- * (list made in November 1996).
- *
- * Original long integer code written by Doug Lea (dl@rocky.oswego.edu).
- * The GNU G++ library's Integer.cc file also has these attributions:
- * Some of the following algorithms are very loosely based on those from
- * MIT C-Scheme bignum.c, which is
- * Copyright (c) 1987 Massachusetts Institute of Technology
- * with other guidance from Knuth, vol. 2
- * Thanks to the creators of the algorithms.
- *
- * NOTES
- * To compile intoids.library, use the SAS C compiler, version 6.56.
- * Use 32 bit integers, 32 bit longs and 16 bit shorts. Naturally, you
- * can use whatever compiler you want to write code for calling the
- * library (SASC and GNU are supported, and there is an .FD file for
- * making interfaces for other compilers). Here's the SCOPTIONS file I
- * used for making intoids.library:
- * PARAMETERS=REGISTERS
- * NOSTACKCHECK
- * NOCHECKABORT
- * ERRORREXX
- * OPTIMIZE
- * LINK
- * LISTMACROS
- * LISTINCLUDES
- * STRINGSCONST
- * OPTIMIZERINLINELOCAL
- * VERBOSE
- * MAP
- * MAPHUNK
- * MAPSYMBOLS
- * MAPLIB
- * MAPXREFERENCE
- * STRICT
- * LIBRARYCODE
- * OPTIMIZERTIME
- * STRINGSECTION=CODE
- * STARTUP=libinit
- * PROGRAMNAME=intoids.library
- * MAPFILE=Intoids.map
- * PUBSCREEN=Workbench
- * LIBRARYFDFILE=Intoids.fd
- * LIBRARYVERSION=1
- * LIBRARYREVISION=0
- * OPTIMIZERCOMPLEXITY=1
- * OPTIMIZERDEPTH=1
- * OPTIMIZERRECURDEPTH=0
- *
- * BUGS
- * Not all the functions from the GNU Integer library were implemented.
- * If you want modulo, power and other functions, either ask me or do it
- * yourself. It's a matter of cutting and pasting the code from GNU's
- * Integer.cc and fixing up a few things to handle Intoids rather than
- * IntReps.
- *
- * SEE ALSO
- * GNU's G++ library Integer.cc file for the original code and yet more
- * arbitrary precision functions.
- *
- *****************************************************************************
- * $Header: Big:Programming/C/Intoids/Library/RCS/Intoids.c,v 1.28 1997/02/12 17:35:04 AGMS Exp $
- *
- * $Log: Intoids.c,v $
- * Revision 1.28 1997/02/12 17:35:04 AGMS
- * Enable custom version string.
- *
- * Revision 1.27 1997/02/12 17:31:43 AGMS
- * Changed some titles for better autodoc index.
- *
- * Revision 1.26 1997/02/12 16:45:08 AGMS
- * Added AGMS Portable Integer Format stuff.
- *
- * Revision 1.25 1997/01/21 17:50:25 AGMS
- * Added autodocs for new AGMS Portable Integer functions.
- *
- * Revision 1.24 1997/01/14 17:12:42 AGMS
- * Added AutoDoc comments for all the exported functions. Realised
- * that there are no portable binary number formats...
- *
- * Revision 1.23 1997/01/14 12:39:26 AGMS
- * Started adding AutoDoc comments.
- *
- * Revision 1.22 1997/01/12 17:57:15 AGMS
- * Fixed a memory leak with multiplying two small integers with a
- * result that didn't fit in a long. Also added more parameter
- * error checking.
- *
- * Revision 1.21 1997/01/12 12:31:53 AGMS
- * Changed to fit in with the standard Amiga C compiler include
- * directory structure. Also uses standard Amiga type names
- * (STRPTR instead of char *). Unfortunately that loses the
- * const declarations for some of the arguments.
- *
- * Revision 1.20 1996/12/29 09:27:58 AGMS
- * *** empty log message ***
- *
- * Revision 1.19 1996/12/29 09:05:02 AGMS
- * Dropped in division functions from the GNU library.
- *
- * Revision 1.18 1996/12/28 13:36:21 AGMS
- * Added remaining multiplication code and some utility functions.
- *
- * Revision 1.17 1996/12/18 16:40:48 AGMS
- * Added functions for negating and comparing Intoids, fixed some bugs.
- *
- * Revision 1.16 1996/12/12 19:26:36 AGMS
- * Found getreg function, can call the utility.library long division
- * routines directly and get both the division result and the remainder.
- *
- * Revision 1.15 1996/12/12 18:22:48 AGMS
- * Adding a long to an IntRep and Multiplying an IntRep by a
- * long now work.
- *
- * Revision 1.14 1996/12/09 16:55:34 AGMS
- * Now use SHORT_PER_LONG and do other things to make it work
- * even for longs that aren't 32 bits (but probably some things
- * still aren't ready for 64 bit longs). Multiplication also
- * under construction.
- *
- * Revision 1.13 1996/12/08 17:22:23 AGMS
- * Addition seems to work, now for multiplication!
- *
- * Revision 1.12 1996/12/08 15:22:15 AGMS
- * Addition functions typed in, ready for testing.
- *
- * Revision 1.11 1996/12/07 17:06:43 AGMS
- * Converted to use less indirection.
- *
- * Revision 1.10 1996/12/07 14:17:21 AGMS
- * Oops, just realised that you don't need the extra level of
- * indirection in Intoids, can point at the IntRep directly,
- * not at a pointer to the IntRep.
- *
- * Revision 1.9 1996/12/04 17:01:31 AGMS
- * Changed some inline functions to be macros for better optimization.
- * ResizeIntoid now leaves old value alone if requested.
- * Added functions for normalizing and copying Intoids.
- * Addition function under construction.
- *
- * Revision 1.8 1996/12/03 16:17:42 AGMS
- * Now with even more international support. Uses Utility.library for
- * 32 bit math (division with remainder mostly).
- *
- * Revision 1.7 1996/11/28 16:04:41 AGMS
- * Typed in stuff needed for printing an Intoid.
- *
- * Revision 1.6 1996/11/23 17:22:49 AGMS
- * Now compiles and operates as a library, still no guts.
- *
- * Revision 1.5 1996/11/21 16:37:30 AGMS
- * Not much.
- *
- * Revision 1.4 1996/11/21 16:16:00 AGMS
- * Now compiles, but doesn't have any guts yet.
- *
- * Revision 1.3 1996/11/18 17:25:09 AGMS
- * Documentation changes.
- *
- * Revision 1.2 1996/11/14 18:00:40 AGMS
- * Added GNU license header info.
- *
- * Revision 1.1 1996/11/14 15:50:03 AGMS
- * Initial revision
- */
-
-
- #define __USE_SYSBASE 1
- /* Need this to make the exec.library headers use the library base global
- variable SysBase in SAS C (otherwise it just uses location $4 which slows
- things down because it is in CHIP memory). */
-
- #include <limits.h> /* For CHAR_BIT definition. */
- #include <string.h> /* For string reverse function. */
- #include <dos.h> /* For getreg builtin function. */
- #include <proto/exec.h>
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <proto/intuition.h>
- #include <proto/locale.h>
- #include <proto/utility.h>
- #include <utility/utility.h>
- #include <libraries/Intoids.h> /* Get datatypes, no function prototypes. */
-
- #if __SASC
- /* Special register assignment keywords (parameters passed in registers,
- not on the stack) for making the library, SAS/C Amiga dialect. */
-
- #define REGA0 register __a0
- #define REGA1 register __a1
- #define REGA6 register __a6
- #define REGD0 register __d0
- #define REGD1 register __d1
-
- /* Declare the function as requiring a reload of the global data
- pointer and as using register arguments. */
-
- #define LIBFUNC __saveds __asm
-
- #else /* Some other compiler. */
- #define REGA0
- #define REGA1
- #define REGA6
- #define REGD0
- #define REGD1
- #define LIBFUNC
- #endif
-
-
- /* Because the debugger doesn't recognize static functions in shared
- libraries, disable the "static" function declaration when doing
- debugging. Of course, it doesn't really matter since most code
- can link with the shared library code only through the exported
- interface (which uses only functions identified as LIBFUNC).
- The exception is the library startup code. */
-
- #if _DEBUG
- #define LOCALFUNC
- #else /* Normal use. */
- #define LOCALFUNC static
- #endif
-
- /* AutoRequestor values for the body text, similar to AUTOFRONTPEN and
- other default values. */
-
- #define BODYLEFTEDGE 6
- #define BODYTOPEDGE 5
-
-
- /*
- Sizes of shifts for multiple-precision arithmetic.
- These should not be changed unless Integer representation
- as unsigned shorts is changed in the implementation files.
-
- Also, some other stuff has been hard coded to use shorts,
- like the macros that strip off the I_SHIFT bits from a
- long integer.
- */
-
- #define I_SHIFT (sizeof(short) * CHAR_BIT)
- #define I_RADIX ((unsigned long)(1L << I_SHIFT))
- #define I_MAXNUM ((unsigned long)((I_RADIX - 1)))
- #define I_MINNUM ((unsigned long)(I_RADIX >> 1))
- #define I_POSITIVE 1
- #define I_NEGATIVE 0
-
- /* All routines assume SHORT_PER_LONG > 1 */
- #define SHORT_PER_LONG ((unsigned)(((sizeof(long) + sizeof(short) - 1) / sizeof(short))))
- #define CHAR_PER_LONG ((unsigned)sizeof(long))
-
- /*
- minimum and maximum sizes for an IntRep (number of shorts in the IntRep
- number storage array).
- */
-
- #define MINIntRep_SIZE 4
- #define MAXIntRep_SIZE I_MAXNUM
-
-
-
- typedef struct IntRepStruct
- {
- unsigned short currentLength; /* Number of entries in numberArray. */
- BOOL positiveSign; /* 1 means >= 0; 0 means < 0. */
- unsigned short allocatedLength; /* 0 means constant. Number of shorts. */
- unsigned short numberArray [1]; /* least significant value in [0]. */
- } IntRep, *IntRepPointer;
- /* Large integer representation, essentially the same as in the GNU G++
- Integer library. The numberArray (and thus the total record size) grows as
- needed. Unused entries in numberArray always contain zero (an algorithm
- invariant), so that it is easier to grow into them. The allocatedLength is
- the number of shorts in numberArray. Zero allocatedLength means that the
- number is a special constant value that should not be freed (allocated as a
- global variable, not dynamically allocated). This special constant feature
- isn't used because Intoids can represent special small integers (like 0 and
- +-1) efficiently. */
-
-
- /* Copied from Intoids.h for easier reference: */
- /* typedef void * Intoid; */
- /* As far as the user sees it, it is an opaque type. Treat it like
- a pointer to a dynamically allocated object, though it sometimes
- isn't and sometimes is. A NULL (zero) value Intoid means that an error
- happened (out of memory, divide by zero, etc) [...] Besides storing really
- big numbers and not-a-number, the Intoids can also represent positive and
- negative infinity. */
-
- typedef IntRepPointer IntoidAsPointer;
- typedef signed long IntoidAsLong;
- /* Intoid encoding: values that are a multiple of 4 are a pointer to an
- IntRep. Odd values are a small integer value shifted left by two, with the
- low bit set (arithmatic shift right by 1 bit to get the integer). Other
- special codes are drawn from values generated by 2 + 4 * n: positive
- infinity as 6, negative infinity as 10, see IntoidSpecialCodes for more
- details. */
-
-
- typedef enum IntoidSpecialCodesEnum
- {
- ISC_NOT_A_NUMBER = 0,
- ISC_POSITIVE_INFINITY,
- ISC_NEGATIVE_INFINITY,
- ISC_MAX
- } IntoidSpecialCodes;
- /* The various special codes, used for non-integer numbers like infinity or
- not-a-number (which is used here as the NULL pointer of numbers). In the
- actual 32 bit Intoid, the value used is 2 + 4 * IntoidSpecialCode. The
- exception is the Intoid of all zero which also corresponds to
- ISC_NOT_A_NUMBER too. Precomputed for INTOID_POSITIVE_INFINITY and
- INTOID_NEGATIVE_INFINITY. */
-
-
-
- /******************************************************************************
- * G L O B A L C O N S T A N T D A T A
- *
- * This stuff gets allocated in the code segment (static const declarations).
- * Since this is a library, it would be wastefully in both code and data
- * segments if we asked for the data segment (all hunks get loaded then the
- * data ones get copied to the separately allocated library base record).
- */
-
- #if 1 /* bleeble */
- const char __far _LibID [] = "intoids 1.0 " __AMIGADATE__
- " (by AGMSmith) ($Id: Intoids.c,v 1.28 1997/02/12 17:35:04 AGMS Exp $)\r\n";
- /* Library version string used in the ROMTag, similar to the VER: full
- version string (if the ROMTag exists, it's string is used by the AmigaDOS
- version command instead of the VER: string). Overrides a string defined by
- the linker, which just says "Version 1.0", this causes a link time error
- (but it still links anyways). */
- #endif
-
-
-
- static const char CreditsMessage [] = /* static const for code segment. */
- "$VER: intoids 1.0 " __AMIGADATE__ " ($Id: Intoids.c,v 1.28 1997/02/12 17:35:04 AGMS Exp $)\n"
- "\n"
- "Intoids.library - An Amiga runtime shared code library for efficiently\n"
- "handling large and small integer values using pointer sized data fields.\n"
- "\n"
- "Modifications for storing smaller integers in 32 bit values and conversion\n"
- "to an Amiga library copyright © 1996 by Alexander G. M. Smith.\n"
- "Original long integer code copyright © 1988 Free Software Foundation.\n"
- "\n"
- "This library is free software; you can redistribute it and/or\n"
- "modify it under the terms of the GNU Library General Public\n"
- "License as published by the Free Software Foundation; either\n"
- "version 2 of the License, or (at your option) any later version.\n"
- "\n"
- "This library is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
- "Library General Public License for more details.\n"
- "\n"
- "You should have received a copy of the GNU Library General Public\n"
- "License along with this library; if not, write to the Free\n"
- "Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
- "\n"
- "Modifications for the Amiga library and 32 bit storage implemented by\n"
- "Alexander G. M. Smith, Ottawa Canada, agmsmith@achilles.net,\n"
- "agmsmith@FreeNet.Carleton.ca, agmsmith@bix.com, 71330.3173@compuserve.com,\n"
- "and probably other places in the future. Send mail to all these addresses\n"
- "to find ones which are still valid (list made in November 1996).\n"
- "\n"
- "Original long integer code written by Doug Lea (dl@rocky.oswego.edu).\n"
- "The GNU G++ library's Integer.cc file also has these attributions:\n"
- " Some of the following algorithms are very loosely based on those from\n"
- " MIT C-Scheme bignum.c, which is\n"
- " Copyright (c) 1987 Massachusetts Institute of Technology\n"
- " with other guidance from Knuth, vol. 2\n"
- " Thanks to the creators of the algorithms.\n";
-
-
-
- static const char * const DefaultErrorStrings [MSG_INTOIDS_MAX] =
- {
- /* MSG_INTOIDS_NOT_A_NUMBER */ "not-a-number",
- /* MSG_INTOIDS_INFINITY */ "infinity",
- /* MSG_INTOIDS_NUMBER_TOO_BIG_TO_PRINT */ "(too big to print)",
- /* MSG_INTOIDS_PRINTING_OUT_OF_MEMORY */ "(out of memory)",
- /* MSG_INTOIDS_NEW_TOO_BIG */ "Attempt to create a number bigger than the maximum allowed size.",
- /* MSG_INTOIDS_INTREP_OUT_OF_MEMORY */ "Out of memory for allocating Intoid data bits.",
- /* MSG_INTOIDS_CREDITS */ CreditsMessage,
- /* MSG_INTOIDS_CONTINUE_SHOWING_ERRORS */ "Continue showing intoids.library error messages?",
- /* MSG_INTOIDS_BAD_INPUT_PARMS */ "Bad function input parameters.",
- /* MSG_INTOIDS_DIVIDE_BY_ZERO */ "Divide by zero.",
- /* MSG_INTOIDS_PI_READ_ERROR */ "Error while reading portable integer data.",
- /* MSG_INTOIDS_PI_WRITE_ERROR */ "Error while writing portable integer data.",
- /* MSG_INTOIDS_PI_SEEK_ERROR */ "Error while seeking in portable integer data.",
- /* MSG_INTOIDS_PI_BAD_FORMAT */ "Portable integer has unusual format, bad data?",
- /* MSG_INTOIDS_UNKNOWN_MESSAGE */ "Unknown error message number used!"
- };
- /* English version of localizable strings used by GetIntoidsMessage. See
- the IntoidStringNumbers typedef for the numbers. */
-
-
-
- /******************************************************************************
- * Things too large to be on the stack or that are global. These are put into
- * the library base record and accessed via a dedicated register, thus a
- * maximum of 32K of global near data. Mostly alphabetical order.
- */
-
- struct IntuitionBase *IntuitionBase;
- struct Library *LocaleBase;
- struct Library *UtilityBase;
- struct ExecBase *SysBase;
- /* Various library base global variables. NULL if the library isn't open,
- our custom startup/exit code opens them and closes them. */
-
-
- struct Catalog *CurrentCatalog;
- /* Used for finding language dependent string messages. NULL if not
- available. Read about locale.library for details. */
-
-
- struct Locale *CurrentLocale;
- /* Identifies the current default locale from locale.library. NULL
- if none available (use our own isspace() etc instead). */
-
-
- BOOL DisplayErrors = TRUE;
- /* TRUE if we are showing error messages, FALSE if the user has canceled
- error message displays (remains FALSE until the library gets flushed from
- memory). */
-
-
- const char *ErrorMessagePntr = CreditsMessage;
- /* Points to the current error message. If no error,
- points to the credits string. */
-
-
-
- /****** intoids.library/GetIntoidsMessage ***********************************
- *
- * NAME
- * GetIntoidsMessage -- Convert a message number to a localised string.
- *
- * SYNOPSIS
- * YourString = GetIntoidsMessage( StringNumber )
- * D0 D0
- *
- * STRPTR GetIntoidsMessage( IntoidStringNumbers );
- *
- * FUNCTION
- * Returns a pointer to a message which corresponds to the string
- * number, the particular string depends on the user's language
- * preferences. The string is obtained from the Intoids.catalog
- * file if the user's language isn't English.
- *
- * INPUTS
- * StringNumber - an enum from 0 to MSG_INTOIDS_MAX-1 that identifies
- * the message you want the international string for. If you ask
- * for a string that doesn't exist, you will get the string
- * for MSG_INTOIDS_UNKNOWN_MESSAGE.
- *
- * RESULT
- * YourString - a pointer to a read-only string which will be valid
- * for as long as intoids.library is open.
- *
- * SEE ALSO
- * locale.library - docs on how locale stuff works.
- * Intoids.h - the enum of all message numbers.
- *
- *****************************************************************************
- */
-
- STRPTR LIBFUNC GetIntoidsMessage (REGD0 IntoidStringNumbers StringNumber)
- {
- STRPTR ReturnValue;
-
- if (StringNumber < 0 || StringNumber >= MSG_INTOIDS_MAX)
- StringNumber = MSG_INTOIDS_UNKNOWN_MESSAGE;
-
- ReturnValue = (STRPTR) (DefaultErrorStrings [StringNumber]);
-
- if (CurrentCatalog != NULL)
- ReturnValue = GetCatalogStr (CurrentCatalog,
- (long) StringNumber, ReturnValue);
-
- return ReturnValue;
- }
-
-
-
- /******************************************************************************
- * Our runtime error message display function. If the user hits Cancel, no
- * more messages will be displayed until the library is flushed from memory.
- */
-
- void LOCALFUNC DisplayErrorMessage (const char *ErrorMessage)
- {
- struct IntuiText CancelIText =
- {
- AUTOFRONTPEN,
- AUTOBACKPEN,
- AUTODRAWMODE,
- AUTOLEFTEDGE,
- AUTOTOPEDGE,
- AUTOITEXTFONT,
- NULL, /* Message string goes here */
- AUTONEXTTEXT
- };
- struct IntuiText ErrorIText = CancelIText;
- struct IntuiText ExplainingIText = CancelIText;
- struct IntuiText OKIText = CancelIText;
- BOOL OKHit;
-
- if (DisplayErrors)
- {
- ErrorIText.LeftEdge = BODYLEFTEDGE;
- ErrorIText.TopEdge = BODYTOPEDGE;
- ErrorIText.IText = (UBYTE *) ErrorMessage;
- ErrorIText.NextText = &ExplainingIText;
-
- ExplainingIText.LeftEdge = BODYLEFTEDGE;
- ExplainingIText.TopEdge = BODYTOPEDGE + 12;
- ExplainingIText.IText = (STRPTR)
- GetIntoidsMessage (MSG_INTOIDS_CONTINUE_SHOWING_ERRORS);
- ExplainingIText.NextText = NULL;
-
- if (CurrentLocale != NULL)
- {
- CancelIText.IText = GetLocaleStr (CurrentLocale, NOSTR);
- OKIText.IText = GetLocaleStr (CurrentLocale, YESSTR);
- }
- else
- {
- CancelIText.IText = (STRPTR) "Cancel";
- OKIText.IText = (STRPTR) "OK";
- }
-
- OKHit = AutoRequest (NULL /* No parent window */,
- &ErrorIText, &OKIText, &CancelIText,
- 0, 0, 512 /* width */, 80 /* height */);
-
- if (!OKHit) /* Cancel selected. Stop showing errors. */
- DisplayErrors = FALSE;
- }
- ErrorMessagePntr = ErrorMessage;
- }
-
-
-
- /****** intoids.library/SmallIntToIntoid ************************************
- *
- * NAME
- * SmallIntToIntoid -- Macro to convert a small value int to an Intoid.
- *
- * SYNOPSIS
- * MyIntoid = SmallIntToIntoid( ANumber )
- *
- * Intoid SmallIntToIntoid( int );
- *
- * FUNCTION
- * Converts a short integer or char (unsigned or signed) to an Intoid.
- * Will also work for long integers if they aren't larger than
- * 0x3FFFFFFF in absolute value. Use LongToIntoid to properly handle
- * larger longs.
- *
- * INPUTS
- * ANumber - some signed or unsigned char, int or long.
- *
- * RESULT
- * MyIntoid - the Intoid equivalent, as a small integer form Intoid.
- * Never returns NULL since it doesn't do memory allocation.
- *
- * NOTES
- * Only works for integers with absolute value of 0x3FFFFFFF or less.
- * Defined in <libraries/Intoids.h>.
- *
- * SEE ALSO
- * LongToIntoid().
- *
- *****************************************************************************
- * looks like: define SmallIntToIntoid(x) ((Intoid) ((((long) (x)) << 1) | 1))
- */
-
-
-
- /******************************************************************************
- * Returns TRUE if the Intoid is a small integer, not a pointer.
- * Small integers have the low bit set and the value in the rest of the bits.
- */
-
- #define IntoidIsSmallInt(x) (((IntoidAsLong) x) & 1)
-
-
-
- /******************************************************************************
- * Returns TRUE if the Intoid is a pointer to an IntRep.
- * The intoid is a pointer if it is a multiple of 4 (assume memory allocation
- * is aligned on 4 or more byte boundaries (Amiga's AllocMem is 8)).
- * Watch out for double evaluation side effects with this one!
- */
-
- #define IntoidIsIntRep(x) (((x) != NULL) && ((((IntoidAsLong) (x)) & 3) == 0))
-
-
-
- /******************************************************************************
- * Returns TRUE if the Intoid contains a special code value. Things like
- * infinity are special codes. Not-a-number is a special kind of special code,
- * represented by a zero Intoid.
- */
-
- #define IntoidIsSpecialCode(x) (((x) == NULL) || \
- ((((IntoidAsLong) (x)) & 3) == 2))
-
-
-
- /******************************************************************************
- * Returns an Intoid for the special code. Note that this doesn't work
- * correctly for ISC_NOT_A_NUMBER (just use NULL instead). Precomputed
- * for INTOID_POSITIVE_INFINITY and INTOID_NEGATIVE_INFINITY.
- */
-
- #define SpecialCodeToIntoid(x) ((Intoid) (((long) (x)) * 4 + 2))
-
-
-
- /******************************************************************************
- * Returns the special code represented by the intoid. Also happens to
- * work for not-a-number (NULL) Intoids.
- */
-
- #define IntoidToSpecialCode(x) \
- ((IntoidSpecialCodes) (((IntoidAsLong) (x)) >> 2))
-
-
-
- /******************************************************************************
- * Returns the small integer an Intoid with the small integer coding
- * represents. You should check with IntoidIsSmallInt before using this
- * function.
- */
-
- #define IntoidToSmallInt(x) (((IntoidAsLong) x) >> 1)
-
-
-
- /******************************************************************************
- * Get low order short's bits from a long. Originally this was an inline
- * function that and'ed the value with I_MAXNUM, but that generated
- * inefficient code with SAS/C (mostly due to casting back and forth).
- */
-
- #define extract(x) ((unsigned short) (x))
-
-
-
- /******************************************************************************
- * Transfer high bits to low. Again, this used to be an inline function
- * that did (x >> I_SHIFT) & I_MAXNUM.
- */
-
- #define down(x) (x >> I_SHIFT)
-
-
-
- /******************************************************************************
- * Transfer low bits to high. Another previously inline function.
- */
-
- #define up(x) (((unsigned long) (x)) << I_SHIFT)
-
-
-
- /******************************************************************************
- * Figure out max length of result of +, -, etc. Returns the larger length
- * plus the pad value. Watch out, evaluates arguments twice.
- */
-
- #define PadLargestLength(len1,len2,pad) \
- ((unsigned long) (((len1) >= (len2)) ? \
- ((unsigned long) (len1) + (unsigned long) (pad)) : \
- ((unsigned long) (len2) + (unsigned long) (pad))))
-
-
-
- /******************************************************************************
- * Compare two equal-length number arrays. Returns x - y, only sign is
- * meaningful (<0 for x<y, ==0 for x==y, >0 for x>y).
- */
-
- long LOCALFUNC __inline CompareNumberArrays (const unsigned short* x,
- const unsigned short* y, unsigned short l)
- {
- long diff = 0;
- const unsigned short* xs = &(x[l]);
- const unsigned short* ys = &(y[l]);
- while (l-- > 0 && (diff = (long) (*--xs) - (long) (*--ys)) == 0)
- ;
- return diff;
- }
-
-
-
- /******************************************************************************
- * Ensure array length & sign are correct (removes leading zeroes from number).
- */
-
- void LOCALFUNC __inline Icheck (IntRepPointer rep)
- {
- unsigned short l = rep->currentLength;
- const unsigned short* p = &(rep->numberArray[l]);
-
- while (l != 0 && *--p == 0)
- --l;
-
- if ((rep->currentLength = (unsigned short) l) == 0)
- rep->positiveSign = I_POSITIVE;
- }
-
-
-
- /******************************************************************************
- * Zero out the end of a rep, including allocated but unused space.
- */
-
- void LOCALFUNC __inline Iclear_from (IntRepPointer rep, unsigned short p)
- {
- unsigned short* cp = &(rep->numberArray[p]);
- const unsigned short* cf = &(rep->numberArray[rep->allocatedLength]);
-
- while(cp < cf)
- *cp++ = 0;
- }
-
-
-
- /******************************************************************************
- * Zero out the part of a rep, from the given spot up to but not including
- * the other spot's index.
- */
-
- void LOCALFUNC __inline Iclear_from_to (IntRepPointer rep,
- unsigned short From, unsigned short To)
- {
- unsigned short* cp = &(rep->numberArray[From]);
- const unsigned short* cf = &(rep->numberArray[To]);
-
- while(cp < cf)
- *cp++ = 0;
- }
-
-
-
-
- /******************************************************************************
- * Copy some of the number part of a rep to another. Like memcpy but copies
- * shorts rather than bytes and the arguments are reversed.
- */
-
- void LOCALFUNC __inline scpy (const unsigned short* src,
- unsigned short* dest, unsigned short nb)
- {
- while (nb-- > 0)
- *dest++ = *src++;
- }
-
-
-
- /******************************************************************************
- * Allocate a new Irep with the given number of shorts available for storage.
- * Returns NULL if it fails. Contents will be initialised to value for zero.
- */
-
- IntRepPointer LOCALFUNC Inew (unsigned long newlen)
- {
- IntRepPointer rep;
- unsigned long siz;
-
- if (newlen > MAXIntRep_SIZE)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_NEW_TOO_BIG));
- return NULL;
- }
-
- if (newlen < MINIntRep_SIZE)
- newlen = MINIntRep_SIZE;
- siz = sizeof(IntRep) +
- ((unsigned long) newlen - 1 /* IntRep includes one short */) * sizeof(short);
-
- rep = AllocMem (siz,
- MEMF_PUBLIC | MEMF_CLEAR /* Initialise new memory to zero */);
-
- if (rep == NULL)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_INTREP_OUT_OF_MEMORY));
- return NULL;
- }
-
- rep->allocatedLength = newlen;
- rep->positiveSign = I_POSITIVE;
- return rep;
- }
-
-
-
- /******************************************************************************
- * Deallocate an Irep.
- */
-
- void LOCALFUNC Idelete (IntRepPointer DeleteMe)
- {
- unsigned long OldLength;
-
- if (DeleteMe != NULL && DeleteMe->allocatedLength != 0)
- {
- OldLength = DeleteMe->allocatedLength;
- DeleteMe->allocatedLength = 0; /* Just for debugging and safety. */
- FreeMem (DeleteMe, sizeof (IntRep) +
- (OldLength - 1 /* IntRep struct includes one short */) * sizeof (short));
- }
- }
-
-
-
- /******************************************************************************
- * Internal function for resizing an IntRep, allocating space if it can't
- * reuse the existing space. Returns NULL if it fails. CurrentLength is set
- * to the new length and any extra words in the number are assumed to be zero
- * (new leading digits are zero). Also zeroes the whole number if requested.
- */
-
- IntRepPointer LOCALFUNC Iresize (IntRepPointer RecycleMe,
- unsigned long NewLength, BOOL ZeroNewValue)
- {
- IntRepPointer NewRep;
- unsigned short OldLength;
-
- if (RecycleMe == NULL)
- NewRep = Inew (NewLength); /* Automatically zero value if successful. */
- else
- {
- OldLength = RecycleMe->currentLength;
- if (NewLength > RecycleMe->allocatedLength)
- {
- NewRep = Inew (NewLength);
- if (NewRep != NULL && !ZeroNewValue)
- {
- scpy (RecycleMe->numberArray, NewRep->numberArray, OldLength);
- NewRep->positiveSign = RecycleMe->positiveSign;
- }
- Idelete (RecycleMe);
- }
- else /* Reusing the IntRep. Adjust it to the new size. */
- {
- NewRep = RecycleMe;
- if (ZeroNewValue)
- {
- /* Just clear the non-zero part of the old one. */
- Iclear_from_to (NewRep, 0, OldLength);
- NewRep->positiveSign = I_POSITIVE;
- }
- else /* Just clear parts that shrink in size. */
- Iclear_from_to (NewRep, (unsigned short) NewLength, OldLength);
- }
- }
-
- if (NewRep != NULL)
- NewRep->currentLength = NewLength;
-
- return NewRep;
- }
-
-
-
- /******************************************************************************
- * Internal function for copying an IntRep to another one, allocating space
- * if it can't overwrite the old one. Handles NULL pointers and duplicate
- * pointers. Returns NULL if it fails. Consider the old one deallocated
- * after this function.
- */
-
- IntRepPointer LOCALFUNC Icopy (IntRepPointer old, const IntRepPointer src)
- {
- unsigned short NewLength;
- IntRepPointer rep;
-
- if (old == src && old != NULL)
- return old;
-
- if (src == NULL) /* Source doesn't exist. */
- {
- if (old == NULL)
- return Inew (0 /* Minimum size will be used, new's value is zero */);
-
- Iclear_from_to (old, 0, old->currentLength);
- old->currentLength = 0;
- old->positiveSign = I_POSITIVE;
- return old;
- }
-
- /* Source exists. Copy it. */
-
- NewLength = src->currentLength;
-
- if (old == NULL || NewLength > old->allocatedLength)
- {
- if (old != NULL) Idelete (old);
- rep = Inew ((unsigned long) NewLength);
- if (rep == NULL) return NULL;
- }
- else /* Can reuse the old one. */
- {
- /* Zero out unused things if old shrinks to new. */
- Iclear_from_to (old, NewLength, old->currentLength);
- rep = old;
- }
- rep->currentLength = NewLength;
- rep->positiveSign = src->positiveSign;
- scpy (src->numberArray, rep->numberArray, NewLength);
-
- return rep;
- }
-
-
-
- /****** intoids.library/FreeIntoid ******************************************
- *
- * NAME
- * FreeIntoid -- Deallocates an Intoid.
- *
- * SYNOPSIS
- * FreeIntoid( RecycleMe )
- * A0
- *
- * void FreeIntoid( Intoid );
- *
- * FUNCTION
- * Deallocates memory used by the given Intoid. OK to pass in NULL.
- * Like regular pointers, you shouldn't use the value in RecycleMe any
- * more after calling this function.
- *
- * INPUTS
- * RecycleMe - a previously allocated Intoid or NULL.
- *
- *****************************************************************************
- */
-
- VOID LIBFUNC FreeIntoid (REGA0 Intoid RecycleMe)
- {
- if (IntoidIsIntRep (RecycleMe))
- {
- Idelete ((IntoidAsPointer) RecycleMe);
- }
- }
-
-
-
- /******************************************************************************
- * Returns an Intoid set up as a pointer to an IntRep which contains at least
- * NewLength shorts in it's numberArray and currentLength set to NewLength.
- * If possible, the memory from RecycleMe is reused. The new Intoid is set to
- * positive zero if requested, otherwise the value is copied from RecycleMe.
- * Returns NULL if it fails (RecycleMe is still deallocated in that case).
- */
-
- Intoid LOCALFUNC ResizeIntoid (Intoid RecycleMe, unsigned long NewLength,
- BOOL ZeroNewValue)
- {
- IntRepPointer NewIntoid;
-
- NewIntoid = Iresize (IntoidIsIntRep (RecycleMe) ?
- (IntoidAsPointer) RecycleMe : NULL, NewLength, ZeroNewValue);
-
- return NewIntoid;
- }
-
-
-
- /******************************************************************************
- * Internal function for adding a Long to an IntRep based Intoid. If NegateB
- * is TRUE then the negative of IntegerB will be added. Handles the case
- * where RecycleMe is the same as IntegerB, avoiding extra allocations.
- * Doesn't normalize the result, so the result is always an IntRep or NULL.
- */
-
- Intoid LOCALFUNC AddLongAndIntRep (long IntegerA, Intoid IntegerB,
- BOOL NegateB, Intoid RecycleMe)
- {
- long ComparisonResult;
- unsigned short *DataResult;
- unsigned short *Data1Source;
- unsigned short *Data1SourceEnd;
- unsigned short *Data2Source;
- unsigned short *Data2SourceEnd;
- unsigned short LengthA;
- unsigned short LengthB;
- IntRepPointer RepB;
- IntRepPointer RepR;
- Intoid Result;
- BOOL SameBR;
- BOOL SignA;
- BOOL SignB;
- unsigned short TempNumberArray [SHORT_PER_LONG];
- unsigned long ULongA;
- unsigned long ULongSum;
-
- if (!IntoidIsIntRep (IntegerB))
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- FreeIntoid (RecycleMe);
- return NULL; /* NULL input or wrong kind of intoid. */
- }
-
- RepB = (IntoidAsPointer) IntegerB;
- LengthB = RepB->currentLength;
- SignB = (NegateB && LengthB != 0) ? !RepB->positiveSign : RepB->positiveSign;
- SameBR = (IntegerB == RecycleMe);
-
- SignA = (IntegerA >= 0);
- ULongA = SignA ? IntegerA : -IntegerA;
-
- if (SignA == SignB) /* Just add the two unsigned values. */
- {
- Result = ResizeIntoid (RecycleMe,
- PadLargestLength (LengthB, SHORT_PER_LONG,
- 1 /* Plus one extra short for overflows */),
- !SameBR /* Zero result if not same as IntegerB, else keep old value */);
-
- if (Result == NULL) return NULL; /* Out of memory. */
-
- RepR = (IntoidAsPointer) Result;
- RepR->positiveSign = SignB;
- DataResult = RepR->numberArray;
- Data1Source = SameBR ? DataResult : RepB->numberArray;
- Data1SourceEnd = Data1Source + LengthB;
- ULongSum = 0;
-
- while (Data1Source < Data1SourceEnd && ULongA != 0)
- {
- ULongSum += (unsigned long) (*Data1Source++) + extract (ULongA);
- ULongA = down (ULongA);
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
-
- while (ULongA != 0) /* Data source has run out first. */
- {
- ULongSum += extract (ULongA);
- ULongA = down (ULongA);
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
-
- while (ULongSum != 0 && Data1Source < Data1SourceEnd)
- {
- ULongSum += (unsigned long) (*Data1Source++);
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
-
- if (ULongSum != 0)
- *DataResult = extract (ULongSum); /* Overflowed after adding numbers. */
- else if (DataResult != Data1Source) /* Copy rest of number if needed. */
- while (Data1Source < Data1SourceEnd)
- *DataResult++ = *Data1Source++;
- }
- else /* Doing a subtraction. */
- {
- /* Put the long value into an array of shorts format. */
-
- LengthA = 0;
- while (ULongA != 0)
- {
- TempNumberArray[LengthA++] = extract (ULongA);
- ULongA = down (ULongA);
- }
-
- /* See which one is bigger, IntegerA or IntegerB. */
-
- ComparisonResult = (long) LengthB - (long) LengthA;
- if (ComparisonResult == 0) /* Same length, compare values. */
- ComparisonResult = CompareNumberArrays (RepB->numberArray,
- TempNumberArray, LengthA);
-
- if (ComparisonResult == 0) /* Result should be zero. */
- {
- Result = ResizeIntoid (RecycleMe, 0, TRUE /* zero it */);
- if (Result == NULL) return NULL; /* Out of memory. */
- RepR = (IntoidAsPointer) Result;
- }
- else /* Do the math. */
- {
- Result = ResizeIntoid (RecycleMe,
- PadLargestLength (LengthB, SHORT_PER_LONG,
- 0 /* no chance of overflow so no pad */),
- !SameBR /* Zero result if not same as IntegerB, else keep old value */);
- if (Result == NULL) return NULL; /* Out of memory. */
-
- RepR = (IntoidAsPointer) Result;
- DataResult = RepR->numberArray;
-
- if (ComparisonResult > 0) /* IntegerB > IntegerA */
- {
- Data1Source = SameBR ? DataResult : RepB->numberArray;
- Data1SourceEnd = Data1Source + LengthB;
- Data2Source = TempNumberArray;
- Data2SourceEnd = Data2Source + LengthA;
- RepR->positiveSign = SignB;
- }
- else /* IntegerB < IntegerA */
- {
- Data1Source = TempNumberArray;
- Data1SourceEnd = Data1Source + LengthA;
- Data2Source = SameBR ? DataResult : RepB->numberArray;
- Data2SourceEnd = Data2Source + LengthB;
- RepR->positiveSign = SignA;
- }
-
- /* Calculate (1 << Largest Length) + Data1Source - Data2Source.
- The (1 << Largest Length) is too big to fit in the result,
- so it seems to be zero as far as the result is concerned.
- It's a way of doing the borrows without using negative numbers. */
-
- ULongSum = 1;
- while (Data2Source < Data2SourceEnd)
- {
- ULongSum += (unsigned long) (*Data1Source++) + I_MAXNUM -
- (unsigned long) (*Data2Source++);
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
-
- /* Finish off the Data1Source, which is known bigger than Data2Source. */
-
- while (ULongSum == 0 && Data1Source < Data1SourceEnd)
- {
- ULongSum = (unsigned long) (*Data1Source++) + I_MAXNUM;
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
-
- if (DataResult != Data1Source) /* Copy rest of number if needed. */
- while (Data1Source < Data1SourceEnd)
- *DataResult++ = *Data1Source++;
- }
- }
- Icheck (RepR);
- return Result;
- }
-
-
-
- /******************************************************************************
- * Internal function for adding two IntRep based Intoids. If NegateX is TRUE
- * then the negative of the appropriate IntegerX will be added. Handles the
- * case where RecycleMe is the same as IntegerX, avoiding extra allocations.
- * Doesn't normalize the result, so the result is always an IntRep or NULL.
- */
-
- Intoid LOCALFUNC AddIntRepAndIntRep (Intoid IntegerA, BOOL NegateA,
- Intoid IntegerB, BOOL NegateB, Intoid RecycleMe)
- {
- long ComparisonResult;
- unsigned short *DataResult;
- unsigned short *Data1Source;
- unsigned short *Data1SourceEnd;
- unsigned short *Data2Source;
- unsigned short *Data2SourceEnd;
- unsigned short LengthA;
- unsigned short LengthB;
- IntRepPointer RepA;
- IntRepPointer RepB;
- IntRepPointer RepR;
- Intoid Result;
- BOOL SameAR;
- BOOL SameBR;
- BOOL SignA;
- BOOL SignB;
- unsigned long ULongSum;
-
- if (!IntoidIsIntRep (IntegerA) || !IntoidIsIntRep (IntegerB))
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- FreeIntoid (RecycleMe);
- return NULL; /* NULL input or wrong kind of intoid. */
- }
-
- RepA = (IntoidAsPointer) IntegerA;
- RepB = (IntoidAsPointer) IntegerB;
-
- LengthA = RepA->currentLength;
- LengthB = RepB->currentLength;
-
- SignA = (NegateA && LengthA != 0) ? !RepA->positiveSign : RepA->positiveSign;
- SignB = (NegateB && LengthB != 0) ? !RepB->positiveSign : RepB->positiveSign;
-
- SameAR = (IntegerA == RecycleMe);
- SameBR = (IntegerB == RecycleMe);
-
- if (SignA == SignB)
- {
- Result = ResizeIntoid (RecycleMe,
- PadLargestLength (LengthA, LengthB,
- 1 /* Plus one extra short for overflows */),
- !(SameAR || SameBR) /* Zero result if result is not an input */);
-
- if (Result == NULL) return NULL; /* Out of memory. */
- RepR = (IntoidAsPointer) Result;
- RepR->positiveSign = SignA;
- DataResult = RepR->numberArray;
-
- /* Associate the longer number with Data1Source. */
-
- if (LengthA >= LengthB)
- {
- Data1Source = SameAR ? RepR->numberArray : RepA->numberArray;
- Data1SourceEnd = Data1Source + LengthA;
- Data2Source = SameBR ? RepR->numberArray : RepB->numberArray;
- Data2SourceEnd = Data2Source + LengthB;
- }
- else /* IntegerB is longer, it is used as Data1Source. */
- {
- Data1Source = SameBR ? RepR->numberArray : RepB->numberArray;
- Data1SourceEnd = Data1Source + LengthB;
- Data2Source = SameAR ? RepR->numberArray : RepA->numberArray;
- Data2SourceEnd = Data2Source + LengthA;
- }
- ULongSum = 0;
- while (Data2Source < Data2SourceEnd)
- {
- ULongSum += (unsigned long) (*Data1Source++) +
- (unsigned long) (*Data2Source++);
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
- while (ULongSum != 0 && Data1Source < Data1SourceEnd)
- {
- ULongSum += (unsigned long) (*Data1Source++);
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
- if (ULongSum != 0) /* Overflowed into last short. */
- *DataResult = extract (ULongSum);
- else /* Copy unchanging high part to result if needed. */
- if (DataResult != Data1Source)
- while (Data1Source < Data1SourceEnd)
- *DataResult++ = *Data1Source++;
- }
- else /* Different signs, do a subtraction. */
- {
- /* See which one is bigger, IntegerA or IntegerB. */
-
- ComparisonResult = (long) LengthA - (long) LengthB;
- if (ComparisonResult == 0) /* Same length, compare values. */
- ComparisonResult = CompareNumberArrays (RepA->numberArray,
- RepB->numberArray, LengthA);
-
- if (ComparisonResult == 0) /* Result should be zero. */
- {
- Result = ResizeIntoid (RecycleMe, 0, TRUE /* zero it */);
- if (Result == NULL) return NULL; /* Out of memory. */
- RepR = (IntoidAsPointer) Result;
- }
- else /* Do the math. */
- {
- Result = ResizeIntoid (RecycleMe,
- PadLargestLength (LengthA, LengthB,
- 0 /* no need for overflow padding */),
- !(SameAR || SameBR) /* Zero result if result is not an input */);
-
- if (Result == NULL) return NULL; /* Out of memory. */
- RepR = (IntoidAsPointer) Result;
- DataResult = RepR->numberArray;
-
- /* Put the larger in magnitude integer in Data1Source. */
-
- if (ComparisonResult > 0) /* If IntegerA > IntegerB */
- {
- Data1Source = SameAR ? DataResult : RepA->numberArray;
- Data1SourceEnd = Data1Source + LengthA;
- Data2Source = SameBR ? DataResult : RepB->numberArray;
- Data2SourceEnd = Data2Source + LengthB;
- RepR->positiveSign = SignA;
- }
- else /* IntegerA < IntegerB */
- {
- Data1Source = SameBR ? DataResult : RepB->numberArray;
- Data1SourceEnd = Data1Source + LengthB;
- Data2Source = SameAR ? DataResult : RepA->numberArray;
- Data2SourceEnd = Data2Source + LengthA;
- RepR->positiveSign = SignB;
- }
-
- /* Calculate (1 << Largest Length) + DataSource - Data2Source.
- The (1 << Largest Length) is too big to fit in the result,
- so it seems to be zero as far as the result is concerned.
- It's a way of doing the borrows without using negative numbers. */
-
- ULongSum = 1;
- while (Data2Source < Data2SourceEnd)
- {
- ULongSum += (unsigned long) (*Data1Source++) + I_MAXNUM -
- (unsigned long) (*Data2Source++);
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
-
- /* Finish off the Data1Source, which is known bigger than Data2Source. */
-
- while (ULongSum == 0 && Data1Source < Data1SourceEnd)
- {
- ULongSum = (unsigned long) (*Data1Source++) + I_MAXNUM;
- *DataResult++ = extract (ULongSum);
- ULongSum = down (ULongSum);
- }
-
- if (DataResult != Data1Source) /* Copy rest of number if needed. */
- while (Data1Source < Data1SourceEnd)
- *DataResult++ = *Data1Source++;
- }
- }
- Icheck (RepR);
- return Result;
- }
-
-
-
- /******************************************************************************
- * Multiply a long and an IntRep based Intoid.
- * Returns an IntRep type Intoid or NULL.
- */
-
- Intoid LOCALFUNC MultiplyLongAndIntRep (long IntegerA, const Intoid IntegerB,
- Intoid RecycleMe)
- {
- unsigned short *Data1Source;
- unsigned short *Data1SourceStart;
- unsigned short *Data2Source;
- unsigned short *Data2SourceEnd;
- unsigned short *Data2SourceStart;
- unsigned short *DataResult;
- unsigned short *DataResultCurrent;
- unsigned short *DataResultEnd;
- unsigned short LengthA;
- unsigned short LengthB;
- unsigned long LengthR;
- unsigned long Multiplier;
- IntRepPointer RepB;
- IntRepPointer RepR;
- Intoid Result;
- BOOL SameBR;
- BOOL SignA;
- BOOL SignB;
- BOOL SignR;
- unsigned long Sum;
- unsigned short TempNumberArray [SHORT_PER_LONG];
- unsigned long ULongA;
-
- /* Get ahold of the IntRep for IntegerB. */
-
- if (!IntoidIsIntRep (IntegerB))
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- FreeIntoid (RecycleMe);
- return NULL; /* NULL input or wrong kind of intoid. */
- }
- RepB = (IntoidAsPointer) IntegerB;
- LengthB = RepB->currentLength;
- SameBR = (IntegerB == RecycleMe);
-
- /* Check for the simple case of multiplying by zero. */
-
- if (LengthB == 0 || IntegerA == 0)
- {
- /* Multiplying by zero gives zero. */
-
- return ResizeIntoid (RecycleMe, 0, TRUE /* zero it */);
- }
-
- /* Check for the simple case of multiplying by one. */
-
- if (IntegerA == 1)
- {
- /* Multiplying by one gives the same number. Use ResizeIntoid
- so that RecycleMe is guaranteed to be an IntRep. Should
- also work if RecycleMe == IntegerB. */
-
- RecycleMe = ResizeIntoid (RecycleMe, (unsigned long) LengthB, FALSE);
- return Icopy (RecycleMe, IntegerB);
- }
-
- /* Figure out the sign of the result, before we start mangling it. */
-
- SignA = (IntegerA >= 0);
- SignB = RepB->positiveSign;
- SignR = (SignA == SignB);
-
- /* Copy our long number into a temporary array of shorts, and
- find out how long it is. */
-
- ULongA = SignA ? IntegerA : -IntegerA;
- LengthA = 0;
- while (ULongA != 0)
- {
- TempNumberArray[LengthA++] = extract (ULongA);
- ULongA = down (ULongA);
- }
-
- /* Allocate space for the result. */
-
- LengthR = (unsigned long) LengthA + (unsigned long) LengthB;
- Result = ResizeIntoid (RecycleMe, LengthR,
- !SameBR /* Zero result if not same as IntegerB, else keep old value */);
-
- if (Result == NULL) return NULL; /* Out of memory. */
- RepR = (IntoidAsPointer) Result;
- RepR->positiveSign = SignR;
-
- /* Set up pointers to sources and destinations. */
-
- DataResult = RepR->numberArray;
- DataResultEnd = DataResult + LengthR;
-
- if (SameBR)
- {
- DataResultCurrent = DataResult + (LengthB - 1);
- Data1SourceStart = DataResult;
- Data1Source = DataResultCurrent;
- Data2SourceStart = TempNumberArray;
- Data2SourceEnd = Data2SourceStart + LengthA;
- }
- else if (LengthB <= LengthA)
- {
- DataResultCurrent = DataResult + (LengthB - 1);
- Data1SourceStart = RepB->numberArray;
- Data1Source = Data1SourceStart + (LengthB - 1);
- Data2SourceStart = TempNumberArray;
- Data2SourceEnd = Data2SourceStart + LengthA;
- }
- else
- {
- DataResultCurrent = DataResult + (LengthA - 1);
- Data1SourceStart = TempNumberArray;
- Data1Source = Data1SourceStart + (LengthA - 1);
- Data2SourceStart = RepB->numberArray;
- Data2SourceEnd = Data2SourceStart + LengthB;
- }
-
- /* And now the big multiplication. Much like you do in school grade 2. */
-
- while (Data1Source >= Data1SourceStart)
- {
- Multiplier = (unsigned long) (*Data1Source--);
- DataResult = DataResultCurrent--;
- *DataResult = 0;
- if (Multiplier != 0)
- {
- Sum = 0;
- Data2Source = Data2SourceStart;
- while (Data2Source < Data2SourceEnd)
- {
- Sum += Multiplier * (unsigned long) (*Data2Source++) +
- (unsigned long) (*DataResult);
- *DataResult++ = extract (Sum);
- Sum = down (Sum);
- }
- while (Sum != 0 && DataResult < DataResultEnd)
- {
- Sum += (unsigned long) (*DataResult);
- *DataResult++ = extract (Sum);
- Sum = down (Sum);
- }
- }
- }
-
- Icheck (RepR);
- return Result;
- }
-
-
-
- /******************************************************************************
- * Multiply two IntReps, returns an IntRep or NULL.
- * Assumes trivial cases done before this (arguments aren't 0 or +-1).
- * Recycles RecycleMe if it isn't NULL, can be the same as either argument or
- * both (special case code for squaring).
- */
-
- IntRepPointer LOCALFUNC MultiplyIntRepAndIntRep (const IntRepPointer x,
- const IntRepPointer y, Intoid RecycleMe)
- {
- IntRepPointer r;
- unsigned short rl; /* Result length. */
- unsigned long rll; /* Long version of length to catch overflows. */
- unsigned short xl;
- unsigned short yl;
- int rsgn;
- int xrsame;
- int yrsame;
- int xysame;
-
- if (!IntoidIsIntRep (x) || !IntoidIsIntRep (y))
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- FreeIntoid (RecycleMe);
- return NULL;
- }
-
- r = IntoidIsIntRep (RecycleMe) ? RecycleMe : NULL;
- xl = x->currentLength;
- yl = y->currentLength;
- rll = (unsigned long) xl + (unsigned long) yl;
- rl = rll;
- rsgn = x->positiveSign == y->positiveSign;
- xrsame = x == r;
- yrsame = y == r;
- xysame = x == y;
-
- if (!(xysame && xrsame))
- {
- unsigned short* rs;
- unsigned short* topr;
- unsigned short* currentr;
- const unsigned short* bota;
- const unsigned short* as;
- const unsigned short* botb;
- const unsigned short* topb;
-
- r = Iresize (r, rll, !(xrsame || yrsame) /* Zero if different vars */);
- if (r == NULL) return NULL;
- rs = r->numberArray;
- topr = &(rs[rl]);
-
- /* use best inner/outer loop params given constraints */
- if (xrsame)
- {
- currentr = &(rs[xl-1]);
- bota = rs;
- as = currentr;
- botb = y->numberArray;
- topb = &(botb[yl]);
- }
- else if (yrsame)
- {
- currentr = &(rs[yl-1]);
- bota = rs;
- as = currentr;
- botb = x->numberArray;
- topb = &(botb[xl]);
- }
- else if (xl <= yl)
- {
- currentr = &(rs[xl-1]);
- bota = x->numberArray;
- as = &(bota[xl-1]);
- botb = y->numberArray;
- topb = &(botb[yl]);
- }
- else
- {
- currentr = &(rs[yl-1]);
- bota = y->numberArray;
- as = &(bota[yl-1]);
- botb = x->numberArray;
- topb = &(botb[xl]);
- }
-
- while (as >= bota)
- {
- unsigned long ai = (unsigned long)(*as--);
- unsigned short* rs = currentr--;
- *rs = 0;
- if (ai != 0)
- {
- unsigned long sum = 0;
- const unsigned short* bs = botb;
- while (bs < topb)
- {
- sum += ai * (unsigned long)(*bs++) + (unsigned long)(*rs);
- *rs++ = extract(sum);
- sum = down(sum);
- }
- while (sum != 0 && rs < topr)
- {
- sum += (unsigned long)(*rs);
- *rs++ = extract(sum);
- sum = down(sum);
- }
- }
- }
- }
- else /* x, y, and r same; compute over diagonals (squaring a number) */
- {
- unsigned short* botr;
- unsigned short* topr;
- unsigned short* rs;
- const unsigned short* bota;
- const unsigned short* loa;
- const unsigned short* hia;
-
- r = Iresize(r, rll, FALSE);
- if (r == NULL) return NULL;
- botr = r->numberArray;
- topr = &(botr[rl]);
- rs = &(botr[rl - 2]);
-
- bota = (xrsame)? botr : x->numberArray;
- loa = &(bota[xl - 1]);
- hia = loa;
-
- for (; rs >= botr; --rs)
- {
- const unsigned short* h = hia;
- const unsigned short* l = loa;
- unsigned long prod = (unsigned long)(*h) * (unsigned long)(*l);
- *rs = 0;
-
- for(;;)
- {
- unsigned short* rt = rs;
- unsigned long sum = prod + (unsigned long)(*rt);
- *rt++ = extract(sum);
- sum = down(sum);
- while (sum != 0 && rt < topr)
- {
- sum += (unsigned long)(*rt);
- *rt++ = extract(sum);
- sum = down(sum);
- }
- if (h > l)
- {
- rt = rs;
- sum = prod + (unsigned long)(*rt);
- *rt++ = extract(sum);
- sum = down(sum);
- while (sum != 0 && rt < topr)
- {
- sum += (unsigned long)(*rt);
- *rt++ = extract(sum);
- sum = down(sum);
- }
- if (--h >= ++l)
- prod = (unsigned long)(*h) * (unsigned long)(*l);
- else
- break;
- }
- else
- break;
- }
- if (loa > bota)
- --loa;
- else
- --hia;
- }
- }
-
- r->positiveSign = rsgn;
- Icheck(r);
- return r;
- }
-
-
-
- /******************************************************************************
- * Divide by single digit, return remainder.
- * If q != 0, then keep the result in q, else just compute remainder.
- */
-
- unsigned short LOCALFUNC unscale (const unsigned short* x, unsigned short xl,
- unsigned short y, unsigned short* q)
- {
- if (xl == 0 || y == 1)
- return 0;
- else if (q != 0)
- {
- unsigned short* botq = q;
- unsigned short* qs = &(botq[xl - 1]);
- const unsigned short* xs = &(x[xl - 1]);
- unsigned long rem = 0;
- while (qs >= botq)
- {
- unsigned long u;
- rem = up(rem) | *xs--;
- #if _AMIGA && __SASC /* Use the utility.library 32 bit math subroutines. */
- u = UDivMod32 (rem, (unsigned long) y);
- rem = getreg (REG_D1);
- #else /* Use compiler's 32 bit math. */
- u = rem / y;
- rem -= u * y;
- #endif
- *qs-- = extract(u);
- }
- return (unsigned short) extract(rem);
- }
- else /* Same loop, a bit faster if just need rem. */
- {
- const unsigned short* botx = x;
- const unsigned short* xs = &(botx[xl - 1]);
- unsigned long rem = 0;
- while (xs >= botx)
- {
- rem = up(rem) | *xs--;
- #if _AMIGA && __SASC /* Use the utility.library 32 bit math subroutines. */
- UDivMod32 (rem, (unsigned long) y);
- rem = getreg (REG_D1);
- #else /* Use compiler's 32 bit math. */
- rem -= (rem / y) * y;
- #endif
- }
- return (unsigned short) extract(rem);
- }
- }
-
-
-
- /******************************************************************************
- * Core division routine.
- */
-
- void LOCALFUNC do_divide (unsigned short* rs,
- const unsigned short* ys, unsigned short yl,
- unsigned short* qs, unsigned short ql)
- {
- const unsigned short* topy = &(ys[yl]);
- unsigned short d1 = ys[yl - 1];
- unsigned short d2 = ys[yl - 2];
-
- int l = ql - 1;
- int i = l + yl;
-
- for (; l >= 0; --l, --i)
- {
- unsigned short qhat; /* guess q */
- if (d1 == rs[i])
- qhat = I_MAXNUM;
- else
- {
- unsigned long lr = up((unsigned long)rs[i]) | rs[i-1];
- qhat = lr / d1;
- }
-
- for(;;) /* adjust q, use CompareNumberArrays to avoid overflow problems */
- {
- unsigned short ts[3];
- unsigned long prod = (unsigned long)d2 * (unsigned long)qhat;
- ts[0] = extract(prod);
- prod = down(prod) + (unsigned long)d1 * (unsigned long)qhat;
- ts[1] = extract(prod);
- ts[2] = extract(down(prod));
- if (CompareNumberArrays(ts, &(rs[i-2]), 3) > 0)
- --qhat;
- else
- break;
- };
-
- /* multiply & subtract */
-
- {
- const unsigned short* yt = ys;
- unsigned short* rt = &(rs[l]);
- unsigned long prod = 0;
- unsigned long hi = 1;
- while (yt < topy)
- {
- prod = (unsigned long)qhat * (unsigned long)(*yt++) + down(prod);
- hi += (unsigned long)(*rt) + I_MAXNUM - (unsigned long)(extract(prod));
- *rt++ = extract(hi);
- hi = down(hi);
- }
- hi += (unsigned long)(*rt) + I_MAXNUM - (unsigned long)(down(prod));
- *rt = extract(hi);
- hi = down(hi);
-
- /* off-by-one, add back */
-
- if (hi == 0)
- {
- --qhat;
- yt = ys;
- rt = &(rs[l]);
- hi = 0;
- while (yt < topy)
- {
- hi = (unsigned long)(*rt) + (unsigned long)(*yt++) + down(hi);
- *rt++ = extract(hi);
- }
- *rt = 0;
- }
- if (qs != 0)
- qs[l] = qhat;
- }
- }
- }
-
-
-
- /******************************************************************************
- * Divides an IntRep by a long. Returns an IntRep or NULL. Assumes
- * y != 0, x > y in magnitude (trivial cases done already).
- */
-
- IntRepPointer LOCALFUNC DivideIntRepByLong (const IntRepPointer x, long y,
- Intoid RecycleMe)
- {
- IntRepPointer q;
- unsigned short xl;
- unsigned short ys[SHORT_PER_LONG];
- unsigned long u;
- int xsgn;
- int ysgn;
- int samesign;
- unsigned short yl;
- long ql;
-
- if (!IntoidIsIntRep (x))
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- FreeIntoid (RecycleMe);
- return NULL;
- }
-
- q = IntoidIsIntRep (RecycleMe) ? (IntoidAsPointer) RecycleMe : NULL;
- xl = x->currentLength;
- xsgn = x->positiveSign;
- ysgn = y >= 0;
- samesign = xsgn == ysgn;
- yl = 0;
-
- if (ysgn)
- u = y;
- else
- u = -y;
- while (u != 0)
- {
- ys[yl++] = extract(u);
- u = down(u);
- }
-
- if (yl == 1) /* If divisor fits in a short. */
- {
- q = Icopy(q, x);
- if (q == NULL) return NULL;
- unscale(q->numberArray, q->currentLength, ys[0], q->numberArray);
- }
- else
- {
- IntRepPointer r = NULL;
- unsigned short prescale = (I_RADIX / (1 + ys[yl - 1]));
- if (prescale != 1)
- {
- unsigned long prod = (unsigned long)prescale * (unsigned long)ys[0];
- ys[0] = extract(prod);
- prod = down(prod) + (unsigned long)prescale * (unsigned long)ys[1];
- ys[1] = extract(prod);
- r = MultiplyLongAndIntRep (((long)prescale & I_MAXNUM), x, r);
- if (r == NULL)
- {
- Idelete (q);
- return NULL;
- }
- }
- else
- {
- r = Iresize (r, xl + 1L, TRUE /* zero it */);
- if (r == NULL)
- {
- Idelete (q);
- return NULL;
- }
- scpy(x->numberArray, r->numberArray, xl);
- }
-
- ql = xl - yl + 1L;
- q = Iresize (q, ql, TRUE /* zero it */);
- if (q == NULL)
- {
- Idelete (r);
- return NULL;
- }
-
- do_divide(r->numberArray, ys, yl, q->numberArray, (unsigned short) ql);
-
- Idelete (r);
- }
- q->positiveSign = samesign;
- Icheck(q);
- return q;
- }
-
-
-
- /******************************************************************************
- * Divides an IntRep by another IntRep, returns an IntRep or NULL. Assumes
- * y != 0, x > y in magnitude (trivial cases done already).
- */
-
- IntRepPointer LOCALFUNC DivideIntRepByIntRep (const IntRepPointer x,
- const IntRepPointer y, Intoid RecycleMe)
- {
- IntRepPointer q;
- unsigned short xl;
- unsigned short yl;
- int xsgn;
- int ysgn;
- int samesign;
- long ql;
-
- if (!IntoidIsIntRep (x) || !IntoidIsIntRep (y))
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- FreeIntoid (RecycleMe);
- return NULL;
- }
-
- q = IntoidIsIntRep (RecycleMe) ? (IntoidAsPointer) RecycleMe : NULL;
- xl = x->currentLength;
- yl = y->currentLength;
- xsgn = x->positiveSign;
- ysgn = y->positiveSign;
- samesign = xsgn == ysgn;
-
- if (yl == 1) /* Fits in a short. */
- {
- q = Icopy(q, x);
- if (q == NULL) return NULL;
- unscale(q->numberArray, q->currentLength,
- y->numberArray[0], q->numberArray);
- }
- else
- {
- IntRepPointer yy = NULL;
- IntRepPointer r = NULL;
- unsigned short prescale = (I_RADIX / (1 + y->numberArray[yl - 1]));
- if (prescale != 1 || y == q)
- {
- yy = MultiplyLongAndIntRep (((long)prescale & I_MAXNUM), y, yy);
- r = MultiplyLongAndIntRep (((long)prescale & I_MAXNUM), x, r);
- if (yy == NULL || r == NULL)
- {
- Idelete (r);
- Idelete (yy);
- Idelete (q);
- return NULL;
- }
- }
- else
- {
- yy = (IntRepPointer) y;
- r = Iresize (r, xl + 1L, TRUE /* zero it */);
- if (r == NULL)
- {
- Idelete (q);
- return NULL;
- }
- scpy(x->numberArray, r->numberArray, xl);
- }
-
- ql = xl - yl + 1L;
- q = Iresize (q, ql, TRUE /* zero it */);
- if (q == NULL)
- {
- Idelete (r);
- if (yy != y) Idelete (yy);
- return NULL;
- }
-
- do_divide(r->numberArray, yy->numberArray, yl, q->numberArray,
- (unsigned short) ql);
-
- if (yy != y) Idelete (yy);
- Idelete (r);
- }
- q->positiveSign = samesign;
- Icheck(q);
- return q;
- }
-
-
-
- /****** intoids.library/GetLastIntoidErrorMessage ***************************
- *
- * NAME
- * GetLastIntoidErrorMessage -- Returns the latest error message.
- *
- * SYNOPSIS
- * MyString = GetLastIntoidErrorMessage( )
- * D0
- *
- * STRPTR GetLastIntoidErrorMessage( VOID );
- *
- * FUNCTION
- * Returns a pointer to the last error message. Maybe be incorrect if
- * you are using multitasking to cause errors (you get the global latest
- * error, not your latest error). Also resets the error message to be
- * the copyright and credits for this library (you get that message if
- * there hasn't been an error since the last call to this function).
- *
- * RESULT
- * MyString - a pointer to a read only string in your favorite language.
- *
- * NOTES
- * The same message was displayed to the user in a system requester,
- * or maybe not if that feature is turned off by the user.
- *
- *****************************************************************************
- */
-
- STRPTR LIBFUNC GetLastIntoidErrorMessage (VOID)
- {
- STRPTR ReturnPointer;
-
- ReturnPointer = (STRPTR) ErrorMessagePntr;
- ErrorMessagePntr = GetIntoidsMessage (MSG_INTOIDS_CREDITS);
- return ReturnPointer;
- }
-
-
-
- /******************************************************************************
- * Returns TRUE if the character is white space. Uses Locale language library
- * if available, otherwise just hack it (avoid ctype array).
- */
-
- BOOL LOCALFUNC MyIsSpace (unsigned long character)
- {
- if (CurrentLocale != NULL)
- return IsSpace (CurrentLocale, character);
-
- return (BOOL) (character == ' ' || character == 9 /* tab char */);
- }
-
-
-
- /****** intoids.library/SignOfIntoid ****************************************
- *
- * NAME
- * SignOfIntoid -- Returns -1, 0 or +1 depending on Intoid's sign.
- *
- * SYNOPSIS
- * MySign = SignOfIntoid( IntegerA )
- * D0 D0
- *
- * LONG SignOfIntoid( Intoid );
- *
- * FUNCTION
- * Fast way of finding the sign of any Intoid.
- *
- * INPUTS
- * IntegerA - any Intoid you want to find the sign of.
- *
- * RESULT
- * MySign - reflects the sign of IntegerA in a LONG value. Returns -1
- * for negative integers (includes negative infinity), 0 for zero
- * and non-numbers, 1 for positive integers (and +infinity).
- *
- * SEE ALSO
- * CompareIntoids(), CompareIntoidMagnitudes().
- *
- *****************************************************************************
- */
-
- LONG LIBFUNC SignOfIntoid (REGD0 Intoid IntegerA)
- {
- IntRepPointer RepA;
- long Sign;
-
- if (IntoidIsSmallInt (IntegerA))
- {
- Sign = IntoidToSmallInt (IntegerA);
- if (Sign < 0)
- Sign = -1L;
- else if (Sign > 0)
- Sign = 1L;
- }
- else if (IntoidIsIntRep (IntegerA))
- {
- RepA = (IntoidAsPointer) IntegerA;
- if (RepA->currentLength == 0) /* Value is IntRep equivalent to zero. */
- Sign = 0;
- else
- Sign = RepA->positiveSign ? 1L : -1L;
- }
- else if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- Sign = 1L;
- else if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- Sign = -1L;
- else /* Some other special code. */
- Sign = 0;
-
- return Sign;
- }
-
-
-
- /****** intoids.library/IntoidFitsInLong ************************************
- *
- * NAME
- * IntoidFitsInLong -- Tests if an Intoid fits in a long int.
- *
- * SYNOPSIS
- * Boolean = IntoidFitsInLong( IntegerA )
- * D0 D0
- *
- * BOOL IntoidFitsInLong( Intoid );
- *
- * FUNCTION
- * Tests if an Intoid can be represented by an ordinary 32 bit long int.
- *
- * INPUTS
- * IntegerA - any Intoid.
- *
- * RESULT
- * Boolean - TRUE if the Intoid can fit into a long integer. Numbers
- * too big, infinities and not-a-number return FALSE.
- *
- * SEE ALSO
- * IntoidToLong().
- *
- *****************************************************************************
- */
-
- BOOL LIBFUNC IntoidFitsInLong (REGD0 Intoid IntegerA)
- {
- int i;
- IntRepPointer MyIntRep;
- BOOL ReturnValue;
-
- if (IntoidIsSmallInt (IntegerA))
- ReturnValue = TRUE;
- else if (IntoidIsIntRep (IntegerA))
- {
- MyIntRep = (IntoidAsPointer) IntegerA;
- if (MyIntRep->currentLength > SHORT_PER_LONG) /* More than 32 bits. */
- ReturnValue = FALSE;
- else if (MyIntRep->currentLength < SHORT_PER_LONG) /* Number has 16 bits or less. */
- ReturnValue = TRUE;
- else /* Unsigned value is same size as a long, 32 bits. */
- {
- if (MyIntRep->positiveSign) /* Positive OK if 0 to 0x7FFFFFFF. */
- {
- if (MyIntRep->numberArray [SHORT_PER_LONG-1] <= 0x7FFFU)
- ReturnValue = TRUE;
- else
- ReturnValue = FALSE;
- }
- else /* Negative with 32 bit value. OK if whole is <= 0x80000000 */
- {
- if (MyIntRep->numberArray [SHORT_PER_LONG-1] <= 0x7FFFU)
- ReturnValue = TRUE;
- else if (MyIntRep->numberArray [SHORT_PER_LONG-1] == 0x8000U)
- {
- /* Check for special case value of 0x80000000. */
-
- i = SHORT_PER_LONG - 2;
- ReturnValue = TRUE;
- while (i >= 0)
- {
- if (MyIntRep->numberArray [i] != 0)
- {
- ReturnValue = FALSE; /* Nope, value is too big to fit. */
- break;
- }
- --i;
- }
- }
- else /* Negative value starting with 0x8001 or larger. Too big. */
- ReturnValue = FALSE;
- }
- }
- }
- else
- ReturnValue = FALSE; /* A special code, can't be represented. */
-
- return ReturnValue;
- }
-
-
-
- /****** intoids.library/IntoidToLong ****************************************
- *
- * NAME
- * IntoidToLong -- Converts an Intoid into a long integer.
- *
- * SYNOPSIS
- * MyLong = IntoidToLong( IntegerA )
- * D0 D0
- *
- * LONG IntoidToLong( Intoid );
- *
- * FUNCTION
- * Converts an Intoid into the closest long integer.
- *
- * INPUTS
- * IntegerA - any Intoid.
- *
- * RESULT
- * MyLong - an ordinary 32 bit long int equal to IntegerA in value, if
- * possible. If IntegerA is too big or too small then you get the
- * largest (0x7FFFFFFF) or smallest (0x80000000) long possible.
- * Plus and minus infinity become largest and smallest longs
- * respectively. Not-a-number becomes zero.
- *
- * SEE ALSO
- * IntoidFitsInLong().
- *
- *****************************************************************************
- */
-
- LONG LIBFUNC IntoidToLong (REGD0 Intoid IntegerA)
- {
- int i;
- IntRepPointer MyIntRep;
- unsigned long NewLong;
- long ReturnValue;
-
- if (IntoidIsSmallInt (IntegerA))
- ReturnValue = IntoidToSmallInt (IntegerA);
- else if (IntoidIsIntRep (IntegerA))
- {
- MyIntRep = (IntoidAsPointer) IntegerA;
-
- if (MyIntRep->currentLength > SHORT_PER_LONG) /* More than 32 bits. */
- {
- if (MyIntRep->positiveSign)
- ReturnValue = LONG_MAX;
- else
- ReturnValue = LONG_MIN;
- }
- else if (MyIntRep->currentLength == 0)
- ReturnValue = 0;
- else if (MyIntRep->currentLength <= SHORT_PER_LONG - 1)
- {
- if (SHORT_PER_LONG > 2)
- {
- NewLong = 0;
- for (i = MyIntRep->currentLength - 1; i >= 0; i--)
- NewLong = up (NewLong) | MyIntRep->numberArray[i];
- }
- else /* 32 bit longs, know there is just 1 short in the number. */
- NewLong = MyIntRep->numberArray[0];
-
- if (MyIntRep->positiveSign)
- ReturnValue = (long) NewLong;
- else
- ReturnValue = -(long) NewLong;
- }
- else /* Value is same length as a long, may or may not overflow. */
- {
- /* Length is 2 shorts, 32 bits, may overflow since we have an unsigned 32
- bit value stored in numberArray and we are converting to a signed
- value. */
-
- if (SHORT_PER_LONG > 2)
- {
- NewLong = 0;
- for (i = SHORT_PER_LONG - 1; i >= 0; i--)
- NewLong = up (NewLong) | MyIntRep->numberArray[i];
- }
- else /* 32 bit longs, know there are 2 shorts in the number. */
- NewLong = up (MyIntRep->numberArray [1]) | MyIntRep->numberArray [0];
-
- if (MyIntRep->positiveSign) /* Positive OK if 0 to 0x7FFFFFFF. */
- {
- ReturnValue = (long) NewLong;
- if (ReturnValue < 0) /* Too big, so it became negative. */
- ReturnValue = LONG_MAX; /* Use largest positive long instead. */
- }
- else /* Negative OK if 0 to 0x80000000. */
- {
- ReturnValue = -(long) NewLong;
- if (ReturnValue >= 0) /* Overflowed, and became positive. */
- ReturnValue = LONG_MIN; /* Use smallest long integer instead. */
- }
- }
- }
- else /* Must be a special code. */
- {
- switch (IntoidToSpecialCode (IntegerA))
- {
- case ISC_POSITIVE_INFINITY:
- ReturnValue = LONG_MAX;
- break;
-
- case ISC_NEGATIVE_INFINITY:
- ReturnValue = LONG_MIN;
- break;
-
- default:
- ReturnValue = 0;
- break;
- }
- }
-
- return ReturnValue;
- }
-
-
-
- /******************************************************************************
- * Converts a long integer into an IntRep.
- */
-
- IntRepPointer LOCALFUNC LongToIntRep (const long LongA, Intoid RecycleMe)
- {
- int i;
- IntRepPointer MyIntRep;
- Intoid NewIntoid;
- unsigned long TempLong;
-
- /* Ok, have to allocate an IntRep type representation, with at least 32 bits
- (2 shorts) of storage. ResizeIntoid sets it's length to 2 shorts and
- sets the rest of the contents to zero, except the first 2 shorts. */
-
- NewIntoid = ResizeIntoid (RecycleMe, SHORT_PER_LONG,
- FALSE /* Don't need to zero it */);
- if (NewIntoid == NULL) return NULL;
-
- MyIntRep = (IntoidAsPointer) NewIntoid;
-
- if (LongA < 0)
- {
- MyIntRep->positiveSign = I_NEGATIVE;
- TempLong = -LongA; /* Should work for even 0x80000000. */
- }
- else /* A positive or zero number. */
- {
- MyIntRep->positiveSign = I_POSITIVE;
- TempLong = LongA;
- }
-
- if (SHORT_PER_LONG > 2)
- {
- for (i = 0; i < SHORT_PER_LONG; i++)
- {
- MyIntRep->numberArray[i] = extract (TempLong);
- TempLong = down (TempLong);
- }
- }
- else /* SHORT_PER_LONG == 2 */
- {
- MyIntRep->numberArray[0] = extract (TempLong);
- MyIntRep->numberArray[1] = extract (down (TempLong));
- }
- Icheck (MyIntRep); /* Reduce currentLength to remove leading zeroes. */
-
- return NewIntoid;
- }
-
-
-
- /****** intoids.library/LongToIntoid ****************************************
- *
- * NAME
- * LongToIntoid -- Converts a long int to an Intoid.
- *
- * SYNOPSIS
- * NewIntoid = LongToIntoid( LongA, RecycleMe )
- * D0 D0 A0
- *
- * Intoid LongToIntoid( LONG, Intoid );
- *
- * FUNCTION
- * Converts a 32 bit long int into an Intoid.
- *
- * INPUTS
- * LongA - the integer you want to convert.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - a newly allocated Intoid with value equal to LongA. NULL
- * if out of memory.
- *
- * SEE ALSO
- * SmallIntToIntoid().
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC LongToIntoid (REGD0 LONG LongA, REGA0 Intoid RecycleMe)
- {
- /* If it fits in 31 bits, we can fit it into an Intoid as a small integer. */
-
- if ((unsigned long) (LONG_MIN >> 1) <= (unsigned long) LongA ||
- (unsigned long) LongA <= (unsigned long) (LONG_MAX >> 1))
- {
- FreeIntoid (RecycleMe);
- return SmallIntToIntoid (LongA);
- }
-
- return LongToIntRep (LongA, RecycleMe);
- }
-
-
-
- /******************************************************************************
- * Reduces the Intoid to the smallest representation technique that can hold
- * the number. Returns the new Intoid, which may be different (the old
- * one may be deleted so don't have any other references to it).
- */
-
- Intoid LOCALFUNC NormalizeIntoid (Intoid IntegerA)
- {
- IntRepPointer Rep;
-
- if (IntoidIsSpecialCode (IntegerA)) /* Includes NULL case. */
- return IntegerA;
-
- if (IntoidIsSmallInt (IntegerA))
- return IntegerA;
-
- /* Must be an IntRep. See if it fits in a small integer. */
-
- Rep = (IntoidAsPointer) IntegerA;
-
- if (Rep->currentLength > SHORT_PER_LONG)
- return IntegerA; /* Definitely far too big to fit in 31 bits. */
-
- /* If the number might fit in 31 bits, including sign.
- Definitely fits in 32 bits, so convert to long and back
- (this also frees the IntRep if it isn't needed). */
-
- if (Rep->currentLength < SHORT_PER_LONG ||
- Rep->numberArray[SHORT_PER_LONG - 1] <= 0x4000U)
- return LongToIntoid (IntoidToLong (IntegerA), IntegerA);
-
- return IntegerA;
- }
-
-
-
- /****** intoids.library/--FileFormat-- **************************************
- *
- * NAME
- * AGMSPortableIntFormat -- Description of the Portable Integer Format.
- *
- * FUNCTION
- * This binary number format has to handle all values that could
- * be represented by an Intoid and has to be efficient in storage
- * space (so that the AGMS virtual file system databases aren't
- * too large). It also has to be machine independant.
- *
- * To make things simpler for current computer architectures, it is
- * based on a variable quantity of 8 bit bytes (almost all computers can
- * pick out an 8 bit byte from their memory efficiently, few can handle
- * arbitrarily large bit aligned data nicely, particularly in the C
- * language).
- *
- * The general format is: FirstByte, optional size extension bytes,
- * optional data bytes.
- *
- * The size extension byte(s) are located just after FirstByte and just
- * before the actual data bytes. If the first size extension byte is
- * 255 (all 1 bits) then the size value is in two bytes after that
- * (least significant byte comes first), and if those are all 1 bits
- * then the size is in the following 4 bytes, and so on, doubling in
- * length if the previous size extension value is all 1 bits. Don't
- * use an extension of zero, that can cause trouble with some code
- * (extensions of zero are used to signal errors in the Intoids code).
- *
- * The number of optional data bytes is defined by the FirstByte and
- * the optional size extension bytes. Large integers are stored as a
- * positive magnitude (the sign is encoded in FirstByte) in the data
- * bytes. The least significant byte comes first, followed by
- * increasingly more significant bytes. This was done because it is
- * easier to shrink or expand from the end of an array rather than the
- * start of an array when a number gets smaller or larger.
- *
- * The first byte can either be a small integer value (so that things
- * like file name string lengths fit in a byte) or part of a larger
- * integer or a special code. Some numbers can be represented in
- * several different ways, you should be able to read all varieties,
- * and preferably write the shortest one. Here is the encoding for the
- * first byte:
- *
- * $0 to $7F:
- * A small positive integer with value 0 to 127 directly
- * corresponding to treating FirstByte as an 8 bit 2's complement
- * integer.
- *
- * $96 to $FF:
- * A small negative integer with value -106 to -1 directly
- * corresponding to treating FirstByte as an 8 bit 2's complement
- * integer.
- *
- * $80 to $87
- * A positive number with 1 to 8 bytes of data following the FirstByte.
- * The number of data bytes is (unsigned byte) FirstByte - $7F. No
- * size extension bytes.
- *
- * $88 to $8F
- * A negative number with 1 to 8 bytes of data following the FirstByte.
- * The number of data bytes is (unsigned byte) FirstByte - $87. No
- * size extension bytes.
- *
- * $90
- * A positive integer. Has a size extension and a data section. The
- * size extension specifies the number of bytes in the data section.
- *
- * $91
- * A negative integer. Has a size extension and a data section. The
- * size extension specifies the number of bytes in the data section.
- *
- * $92
- * Signals that an extended special code follows, the size extension
- * bytes specify the special code. There is no data section. Note
- * that we want to avoid a size extension of zero (causes trouble),
- * so the special codes start at 1.
- *
- * $93 to $95
- * A special code number. The particular one is FirstByte - $92.
- * There is no data section or size extension. The special codes are:
- * 1: Positive integer infinity.
- * 2: Negative integer infinity.
- * 3: Not a number. The NULL pointer of numbers. The quiet kind
- * of not-a-number (doesn't raise error conditions when used).
- * 4: Noisy variety of not-a-number. Generates an error if used
- * in math? Intoids don't support it. Uses FirstByte $92
- * style encoding.
- * 5+: Future use, uses FirstByte $92 style for encoding.
- *
- *
- * EXAMPLE
- * 00
- * A positive integer with a value of zero. No size extension or
- * data bytes.
- *
- * F6
- * A negative integer with a value of -10. No size extension or
- * data bytes.
- *
- * 80 C8
- * A positive integer with no size extension and 1 ($80 - $7F = 1)
- * data byte. It has a value of +200.
- *
- * 8B 00 CA 9A 3B
- * A negative integer with no size extension and 4 ($8B - $87 = 4)
- * data bytes. It has a value of -$3B9ACA00 = -1000000000.
- *
- * 90 12 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18
- * A positive integer with a size extension of $12 = 18, and 18 data
- * bytes. It has a value of $181716151413121110090807060504030201.
- *
- * 90 FF 23 01 (FF repeated 291 times)
- * A positive integer with a size extension of $123 = 291 (note the
- * first size extension byte is $FF which means see the next two
- * bytes ($23 $01) for the size extension). The data section has
- * 291 bytes of $FF each. This is an integer with a value of
- * 2^2328 - 1.
- *
- * 93
- * Special code 1, meaning positive infinity.
- *
- * 94
- * Special code 2, meaning negative infinity.
- *
- * 95
- * This is special code 3, the code for a quiet not-a-number.
- *
- * 92 04
- * Special code number 4, error signalling variety of not-a-number.
- *
- * 92 FF 23 01
- * Special code number $123 = 291. Currently not defined to mean
- * anything (future use). No data section even though it has size
- * extension bytes.
- *
- * 91 FF FF FF 78 56 34 12 01 02 03 [and 305419893 more bytes here]
- * This is a negative integer with $12345678 = 305419896 bytes of
- * number in the data section. Note the way the size extension grew
- * to hold the size of $12345678. Most current computers would have
- * trouble loading this 300 megabyte number into memory, let alone
- * multiplying it with another one.
- *
- *****************************************************************************
- */
-
-
-
- /****** intoids.library/--UserCallBackStreamFunction-- **********************
- *
- * NAME
- * AGMSPortableIntStreamCallBack -- User defined function for stream IO.
- *
- * SYNOPSIS
- * LONG STACKCALL AGMSPortableIntStreamCallBack (
- * ULONG Operation, APTR Buffer, LONG Amount, APTR UserPntr );
- *
- * FUNCTION
- * A user defined callback function that is used for reading and writing
- * AGMS Portable Integer numbers from or to a stream.
- *
- * INPUTS
- * Operation - this argument specifies what your function should do:
- * 0: Read data. Fill the buffer with Amount data bytes. Your
- * function returns the amount read, which will be less than
- * the Amount requested if it fails (end of file etc).
- * 1: Seek. Seek relative to the current stream postion by
- * Amount bytes. Amount is negative for seeking backwards,
- * but PortableInt functions will never do that. Returns
- * the position in the stream if known, or just zero when
- * it succeeds, returns -1 if it fails (seek past EOF or
- * before start of file, IO errors). Return -2 if you don't
- * implement seek, and a bunch of reads will be used instead.
- * 2: Write data. Write Amount bytes from the buffer to the
- * stream. Returns the amount written, which will be less
- * than the Amount requested if it fails (IO error etc).
- * N: For other unsupported Operation values please return -2.
- * Buffer - points to a buffer where the read in data is saved or
- * the data to be written is obtained.
- * Amount - used to specify the number of bytes to
- * read, skip over, or write.
- * UserPntr - the same value as passed into the original
- * PortableInt function call. Usually will be a file
- * handle or something similar.
- *
- * RESULT
- * ActualAmount - the function returns the number of bytes actually
- * read or written, or the absolute file position after a seek.
- *
- * NOTES
- * The callback function is called using the C language stack
- * based calling convention. In SAS C this is specified with
- * the __stdargs keywords.
- *
- * BUGS
- * Returned seek position value only good for files up to 2G.
- *
- * SEE ALSO
- * PortIntCallBackOp enum in Intoids.h, STACKCALL macro in Intoids.h.
- *
- *****************************************************************************
- */
-
-
-
- /******************************************************************************
- * Read the multibyte extension number from the stream. Returns 0 if
- * something goes wrong. The extension is initially 1 byte long, if that is
- * all 1 bits (value 0xFF) then read the next two bytes. If they are all
- * 1's then read the next 4 bytes, and so on, doubling the number of bytes
- * read. Fails if the extension value is too big for a long integer. Also
- * returns the number of bytes actually read, if ByteCountPntr isn't NULL.
- */
-
- ULONG LOCALFUNC ReadExtensionValue (PortIntCallBackPntr CallBack,
- APTR UserPntr, ULONG *ByteCountPntr)
- {
- LONG ActualIOResult;
- UBYTE ByteArray [CHAR_PER_LONG];
- ULONG ByteCount;
- ULONG ExtensionFullCode;
- ULONG ExtensionValue;
- int i;
- LONG ReadSize;
-
- ByteCount = 0;
- ReadSize = 1;
- ExtensionValue = ExtensionFullCode = 0;
-
- while (ExtensionValue == ExtensionFullCode)
- {
- if (ReadSize > CHAR_PER_LONG)
- {
- /* Extension is bigger than what fits in a long. */
-
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
- ExtensionValue = 0; /* Signal an error. */
- break;
- }
-
- /* Read in the next extension value's bytes. */
-
- ActualIOResult = (* CallBack) (PICBOP_READ, ByteArray, ReadSize, UserPntr);
- ByteCount += ActualIOResult;
- if (ActualIOResult != ReadSize)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
- ExtensionValue = 0; /* Signal an error. */
- break;
- }
-
- /* Convert from little endian to native format. */
-
- ExtensionValue = 0;
- for (i = ReadSize - 1; i >= 0 ; --i)
- {
- ExtensionValue <<= 8;
- ExtensionValue |= ByteArray[i];
- }
-
- /* Generate all 1 bits in ReadSize bytes for
- the current ExtensionFullCode. */
-
- ExtensionFullCode = (1UL << (8 * ReadSize)) - 1UL;
-
- /* Double the size for next read attempt. */
-
- ReadSize += ReadSize;
- }
-
- /* Return the results. */
-
- if (ByteCountPntr != NULL)
- *ByteCountPntr = ByteCount;
-
- return ExtensionValue;
- }
-
-
-
- /******************************************************************************
- * Read the header information from an AGMS Portable Integer. Returns
- * optional number of bytes read, kind of number, auxiliary value (either
- * the small integer or special code or number of bytes in a large integer),
- * and a success flag (TRUE for success, FALSE for error). Fails on IO
- * errors and size extension field being too big to fit in a long.
- */
-
- typedef enum NumberTypeEnum
- {
- PI_SPECIAL_CODE,
- PI_SMALL_INTEGER,
- PI_LARGE_POSITIVE_INTEGER,
- PI_LARGE_NEGATIVE_INTEGER,
- } NumberType;
-
- BOOL LOCALFUNC ReadPortableIntHeader (PortIntCallBackPntr CallBack,
- APTR UserPntr, ULONG *ByteCountPntr, NumberType *NumberKindPntr,
- ULONG *AuxiliaryDataPntr)
- {
- LONG ActualIOResult;
- ULONG AuxiliaryData;
- ULONG ByteCount;
- UBYTE FirstByte;
- NumberType NumberKind;
- BOOL ReturnCode;
- UBYTE UByteOnStack;
- ULONG ULongOnStack;
-
- ReturnCode = FALSE; /* Default failure. */
- ByteCount = AuxiliaryData = NumberKind = 0;
-
- if (CallBack == NULL)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- goto FunctionExit;
- }
-
- /* Get the FirstByte of the number. */
-
- ActualIOResult = (* CallBack) (PICBOP_READ, &UByteOnStack, 1, UserPntr);
- FirstByte = UByteOnStack;
- ByteCount += ActualIOResult;
- if (ActualIOResult != 1)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
- goto FunctionExit;
- }
-
- /* Decode the NumberKind and read size extension if needed. */
-
- if (FirstByte <= 0x7FU) /* A positive small integer. */
- {
- NumberKind = PI_SMALL_INTEGER;
- AuxiliaryData = FirstByte;
- }
- else if (FirstByte >= 0x96U) /* A negative small integer. */
- {
- NumberKind = PI_SMALL_INTEGER;
- AuxiliaryData = (long) (signed char) FirstByte; /* Sign extend it. */
- }
- else if (FirstByte <= 0x87U) /* A positive large integer, $80 to $87. */
- {
- NumberKind = PI_LARGE_POSITIVE_INTEGER;
- AuxiliaryData = FirstByte - 0x7FU; /* Length in bytes. */
- }
- else if (FirstByte <= 0x8FU) /* A negative large integer, $88 to $8F. */
- {
- NumberKind = PI_LARGE_NEGATIVE_INTEGER;
- AuxiliaryData = FirstByte - 0x87U; /* Length in bytes. */
- }
- else if (FirstByte == 0x90U) /* A positive large integer, variable size. */
- {
- NumberKind = PI_LARGE_POSITIVE_INTEGER;
- AuxiliaryData = ReadExtensionValue (CallBack, UserPntr, &ULongOnStack);
- ByteCount += ULongOnStack;
- if (AuxiliaryData == 0)
- goto FunctionExit; /* Error while reading size extension. */
- }
- else if (FirstByte == 0x91U) /* A negative large integer, variable size. */
- {
- NumberKind = PI_LARGE_NEGATIVE_INTEGER;
- AuxiliaryData = ReadExtensionValue (CallBack, UserPntr, &ULongOnStack);
- ByteCount += ULongOnStack;
- if (AuxiliaryData == 0)
- goto FunctionExit; /* Error while reading size extension. */
- }
- else if (FirstByte == 0x92U) /* A special code, size is code's value. */
- {
- NumberKind = PI_SPECIAL_CODE;
- AuxiliaryData = ReadExtensionValue (CallBack, UserPntr, &ULongOnStack);
- ByteCount += ULongOnStack;
- if (AuxiliaryData == 0)
- goto FunctionExit; /* Error while reading size extension. */
- }
- else /* $93 to $95, a special code. */
- {
- NumberKind = PI_SPECIAL_CODE;
- AuxiliaryData = FirstByte - 0x92U;
- }
-
- ReturnCode = TRUE; /* Success at last. */
-
- FunctionExit:
- /* Stuff the return values into their memory locations. */
-
- if (ByteCountPntr != NULL)
- *ByteCountPntr = ByteCount;
-
- *NumberKindPntr = NumberKind;
- *AuxiliaryDataPntr = AuxiliaryData;
-
- return ReturnCode;
- }
-
-
-
- /******************************************************************************
- * This callback function converts a buffer into a stream. In other words, it
- * handles reading, writing and seeking. The end of the buffer corresponds to
- * the end of the stream. See PortIntCallBackPntr in Intoids.h for details.
- */
-
- typedef struct BufferStreamStruct
- {
- UBYTE *start; /* Points to start of user's buffer. */
- UBYTE *end; /* Points just past end of user's buffer. */
- UBYTE *current; /* Current position in user's buffer. */
- } BufferStreamRecord, *BufferStreamPointer;
-
-
- LONG STACKCALL BufferAsStreamCallBack (ULONG Operation, APTR Buffer,
- LONG Amount, APTR UserPntr)
- {
- LONG ActualAmount;
-
- BufferStreamPointer UsersBufferInfo;
-
- UsersBufferInfo = UserPntr;
-
- switch (Operation)
- {
- case PICBOP_READ:
- ActualAmount = UsersBufferInfo->end - UsersBufferInfo->current;
- if (ActualAmount > Amount)
- ActualAmount = Amount;
- if (ActualAmount > 0)
- {
- memcpy (Buffer, UsersBufferInfo->current, (size_t) ActualAmount);
- UsersBufferInfo->current += ActualAmount;
- }
- else /* Zero or negative amount to copy. Do nothing. */
- ActualAmount = 0;
- return ActualAmount;
-
- case PICBOP_SEEK:
- if (Amount >= 0)
- {
- ActualAmount = UsersBufferInfo->end - UsersBufferInfo->current;
- if (ActualAmount >= Amount) /* Enough space to do the seek. */
- {
- UsersBufferInfo->current += Amount;
- return UsersBufferInfo->current - UsersBufferInfo->start;
- }
- return -1; /* Can't seek that far. */
- }
- /* Seeking backwards. */
- ActualAmount = UsersBufferInfo->start - UsersBufferInfo->current;
- if (ActualAmount <= Amount) /* Enough space to do the seek. */
- {
- UsersBufferInfo->current += Amount;
- return UsersBufferInfo->current - UsersBufferInfo->start;
- }
- return -1; /* Can't seek that far. */
-
- case PICBOP_WRITE:
- ActualAmount = UsersBufferInfo->end - UsersBufferInfo->current;
- if (ActualAmount > Amount)
- ActualAmount = Amount;
- if (ActualAmount > 0)
- {
- memcpy (UsersBufferInfo->current, Buffer, (size_t) ActualAmount);
- UsersBufferInfo->current += ActualAmount;
- }
- else /* Zero or negative amount to copy. Do nothing. */
- ActualAmount = 0;
- return ActualAmount;
- }
-
- return -2; /* Unimplemented operation. */
- }
-
-
-
- /****** intoids.library/PortableIntLengthViaCallBack ************************
- *
- * NAME
- * PortableIntLengthViaCallBack -- Gets byte size of portable integer.
- *
- * SYNOPSIS
- * Length = PortableIntLengthViaCallBack( CallBack, UserPntr )
- * D0 D0 D1
- *
- * ULONG PortableIntLengthViaCallBack( PortIntCallBackPntr, APTR );
- *
- * FUNCTION
- * Finds the length in bytes of an AGMS Portable Integer and skips
- * over it.
- *
- * INPUTS
- * CallBack - a user provided function that handles the input
- * stream, see the intoids.library/AGMSPortableIntStreamCallBack
- * entry in these autodocs for details.
- * UserPntr - Any pointer sized value you want. This value will be
- * passed to your callback function. Typically used for file
- * handles.
- *
- * RESULT
- * Length - returns the length or zero if something went wrong (read
- * error or unsupported number kind or bad number format, in which
- * case an unknown number of bytes will have been read). Length
- * includes the header size.
- *
- * NOTES
- * As a side effect, it has read all the bytes in the number. You can
- * use this function to skip over a number (it seeks past the number
- * contents for big numbers).
- *
- * BUGS
- * Doesn't work for numbers that take more than 2 Gigabytes of storage
- * space (garbage results in that case, and unpredictable number of
- * bytes read in that case too - but then that would be a very big
- * number that nobody would ever use, well except when trying to foil
- * nanotechnology based decryption systems :-).
- *
- * SEE ALSO
- * PortableIntLengthViaBuffer(), AGMSPortableIntStreamCallBack.
- *
- *****************************************************************************
- */
-
- ULONG LIBFUNC PortableIntLengthViaCallBack (
- REGD0 PortIntCallBackPntr CallBack,
- REGD1 APTR UserPntr)
- {
- LONG ActualIOResult;
- ULONG Amount;
- ULONG ByteCount;
- ULONG DataSize;
- ULONG NumberKind;
- char TempBuffer [20];
-
- if (!ReadPortableIntHeader (CallBack, UserPntr,
- &ByteCount, &NumberKind, &DataSize))
- return 0; /* Some sort of error. */
-
- /* Skip over the actual data bytes, if any. */
-
- if (NumberKind == PI_LARGE_POSITIVE_INTEGER ||
- NumberKind == PI_LARGE_NEGATIVE_INTEGER)
- {
- ActualIOResult = (* CallBack) (PICBOP_SEEK, NULL, DataSize, UserPntr);
- if (ActualIOResult == -1 /* Seek returns -1 for errors. */)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_SEEK_ERROR));
- return 0;
- }
- if (ActualIOResult == -2 /* Seek returns -2 for unimplemented. */)
- {
- /* Simulate a seek by doing a bunch of reads. */
-
- while (DataSize > 0)
- {
- if (DataSize > sizeof (TempBuffer))
- Amount = sizeof (TempBuffer);
- else
- Amount = DataSize;
-
- ActualIOResult = (* CallBack) (PICBOP_READ,
- TempBuffer, Amount, UserPntr);
- ByteCount += ActualIOResult;
- DataSize -= ActualIOResult;
-
- if (ActualIOResult != Amount)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
- return 0;
- }
- }
- }
- else /* Successful seek. */
- ByteCount += DataSize;
- }
-
- return ByteCount;
- }
-
-
-
- /****** intoids.library/PortableIntLengthViaBuffer **************************
- *
- * NAME
- * PortableIntLengthViaBuffer -- Gets byte size of portable integer.
- *
- * SYNOPSIS
- * Length = PortableIntLengthViaBuffer( Buffer, BufferSize )
- * D0 A0 D1
- *
- * ULONG PortableIntLengthViaBuffer( APTR, ULONG );
- *
- * FUNCTION
- * Finds the length in bytes of an AGMS Portable Integer in a buffer.
- *
- * INPUTS
- * Buffer - points to an area of memory containing the portable integer.
- * BufferSize - amount of data in the buffer.
- *
- * RESULT
- * Length - returns the length or zero if something went wrong (hit end
- * of buffer before number completed, unsupported number kind or bad
- * number format). Length includes the header size.
- *
- * BUGS
- * Doesn't work for numbers that take more than 2 Gigabytes of storage
- * space (garbage results in that case - but then that would be a very
- * big number that nobody would ever use, well maybe we could return an
- * Intoid instead of a ULONG :-).
- *
- * SEE ALSO
- * PortableIntLengthViaCallBack().
- *
- *****************************************************************************
- */
-
- ULONG LIBFUNC PortableIntLengthViaBuffer (
- REGA0 APTR Buffer,
- REGD1 ULONG BufferSize)
- {
- BufferStreamRecord BufferAsStream;
-
- BufferAsStream.current = BufferAsStream.start = Buffer;
- BufferAsStream.end = (UBYTE *) Buffer + BufferSize;
-
- return PortableIntLengthViaCallBack (BufferAsStreamCallBack,
- &BufferAsStream);
- }
-
-
-
- /****** intoids.library/PortableIntToIntoidViaCallBack **********************
- *
- * NAME
- * PortableIntToIntoidViaCallBack -- Converts portable int to Intoid.
- *
- * SYNOPSIS
- * NewIntoid = PortableIntToIntoidViaCallBack
- * ( CallBack, UserPntr, AmountReadPntr, RecycleMe )
- * D0 A0 D0 A1 D1
- *
- * Intoid PortableIntToIntoidViaCallBack
- * ( PortIntCallBackPntr, APTR, ULONG *, Intoid );
- *
- * FUNCTION
- * Reads an arbitrarily long integer in AGMS Portable Integer format
- * from some input stream and returns the result as an Intoid.
- *
- * INPUTS
- * CallBack - a user provided function that handles the input
- * stream, see the intoids.library/AGMSPortableIntStreamCallBack
- * entry in these autodocs for details.
- * UserPntr - Any pointer sized value you want. This value will be
- * passed to your callback function. Typically used for file
- * handles.
- * AmountReadPntr - points to a long variable where the number of bytes
- * read will be placed. Set to NULL if you don't want to use this
- * feature.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - an Intoid equivalent to the number, or NULL if it fails,
- * also NULL if the number is not-a-number.
- * AmountReadPntr - pointed to variable is updated with the number of
- * bytes that were actually read.
- *
- * NOTES
- * Advances the stream to just past the number, if it succeded.
- *
- * BUGS
- * Doesn't work with numbers over 2G in storage space, but they won't fit
- * in an Intoid anyways (128K bytes max in an Intoid).
- *
- * SEE ALSO
- * PortableIntToIntoidViaBuffer(), AGMSPortableIntStreamCallBack.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC PortableIntToIntoidViaCallBack (
- REGA0 PortIntCallBackPntr CallBack,
- REGD0 APTR UserPntr,
- REGA1 ULONG *AmountReadPntr,
- REGD1 Intoid RecycleMe)
- {
- ULONG AuxiliaryData;
- LONG ActualIOResult;
- ULONG ByteCount;
- Intoid NewIntoid;
- IntRepPointer NewIntRep;
- NumberType NumberKind;
- unsigned short *ShortPntr;
- ULONG ShortSize;
- BOOL Success;
- unsigned short TempShort;
- ULONG ULongOnStack;
-
- NewIntoid = NULL; /* Default return value for error conditions. */
- ByteCount = 0;
-
- Success = ReadPortableIntHeader (CallBack, UserPntr, &ULongOnStack,
- &NumberKind, &AuxiliaryData);
- ByteCount += ULongOnStack;
- if (!Success) /* Error while reading header? */
- {
- FreeIntoid (RecycleMe);
- goto FunctionExit;
- }
-
- switch (NumberKind)
- {
- case PI_SMALL_INTEGER:
- NewIntoid = SmallIntToIntoid (AuxiliaryData);
- break;
-
-
- case PI_LARGE_POSITIVE_INTEGER:
- case PI_LARGE_NEGATIVE_INTEGER:
-
- /* Allocate an Intoid large enough to hold the number. */
-
- ShortSize = (AuxiliaryData + sizeof (short) - 1) / sizeof (short);
- if (ShortSize <= 0) /* Some sort of bug. */
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
- FreeIntoid (RecycleMe);
- break;
- }
- NewIntoid = ResizeIntoid (RecycleMe, ShortSize,
- FALSE /* don't bother zeroing ShortSize part of it */);
- if (NewIntoid == NULL)
- break; /* Out of memory. */
- NewIntRep = (IntoidAsPointer) NewIntoid;
-
- /* Read in the number's magnitude bytes. */
-
- NewIntRep->numberArray[ShortSize-1] = 0; /* So high byte is zero. */
- ActualIOResult = (* CallBack) (PICBOP_READ, NewIntRep->numberArray,
- AuxiliaryData, UserPntr);
- ByteCount += ActualIOResult;
- if (ActualIOResult != AuxiliaryData)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
- FreeIntoid (NewIntoid);
- NewIntoid = NULL;
- break;
- }
-
- /* Reverse the bytes in each short integer, if this computer
- uses most significant byte first order. */
-
- #if _M68000 /* Motorola 68000 series CPUs uses MSB order. */
- ShortPntr = NewIntRep->numberArray + ShortSize;
- do
- {
- TempShort = *--ShortPntr;
- *ShortPntr = (TempShort << 8) | (TempShort >> 8);
- } while (ShortPntr != NewIntRep->numberArray);
- #endif /* _M68000 */
-
- /* Normalise the result so it is a valid Intoid. */
-
- NewIntRep->positiveSign = (NumberKind == PI_LARGE_POSITIVE_INTEGER);
- Icheck (NewIntRep);
- NewIntoid = NormalizeIntoid (NewIntoid);
- break;
-
-
- case PI_SPECIAL_CODE:
- FreeIntoid (RecycleMe);
- if (AuxiliaryData == 1)
- {
- NewIntoid = INTOID_POSITIVE_INFINITY;
- break;
- }
- else if (AuxiliaryData == 2)
- {
- NewIntoid = INTOID_NEGATIVE_INFINITY;
- break;
- }
- else if (AuxiliaryData == 3 || AuxiliaryData == 4)
- {
- NewIntoid = NULL; /* Quiet and noisy not-a-number become NULL. */
- break;
- }
- /* Otherwise an unknown special code. */
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
- break;
-
-
- default: /* Unknown kind. */
- FreeIntoid (RecycleMe);
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
- break;
- }
-
- /* Set various return values and return. */
-
- FunctionExit:
- if (AmountReadPntr != NULL)
- *AmountReadPntr = ByteCount;
-
- return NewIntoid;
- }
-
-
-
- /****** intoids.library/PortableIntToIntoidViaBuffer ************************
- *
- * NAME
- * PortableIntToIntoidViaBuffer -- Converts portable int to Intoid.
- *
- * SYNOPSIS
- * NewIntoid = PortableIntToIntoidViaBuffer
- * ( Buffer, BufferSize, AmountReadPntr, RecycleMe )
- * D0 A0 D0 A1 D1
- *
- * Intoid PortableIntToIntoidViaBuffer( APTR, ULONG, ULONG *, Intoid );
- *
- * FUNCTION
- * Reads an arbitrarily long integer in AGMS Portable Integer format
- * from a buffer and returns the Intoid equivalent.
- *
- * INPUTS
- * Buffer - points to an area of memory containing the portable integer.
- * BufferSize - amount of data in the buffer. Has to be at least
- * enough for the entire portable integer, or you get NULL returned.
- * AmountReadPntr - points to a long variable where the number of bytes
- * read will be placed. Set to NULL if you don't want to use this
- * feature.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - an Intoid equivalent to the number, or NULL if it fails,
- * also NULL if the number is not-a-number.
- * AmountReadPntr - pointed to variable is updated with the number of
- * bytes that were actually read, will be from zero to BufferSize.
- *
- * BUGS
- * Doesn't work with numbers over 2G in storage space, but they won't fit
- * in an Intoid anyways (128K bytes max in an Intoid) or even in most
- * system's memory.
- *
- * SEE ALSO
- * PortableIntToIntoidViaCallBack().
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC PortableIntToIntoidViaBuffer (
- REGA0 APTR Buffer,
- REGD0 ULONG BufferSize,
- REGA1 ULONG *AmountReadPntr,
- REGD1 Intoid RecycleMe)
- {
- BufferStreamRecord BufferAsStream;
-
- BufferAsStream.current = BufferAsStream.start = Buffer;
- BufferAsStream.end = (UBYTE *) Buffer + BufferSize;
-
- return PortableIntToIntoidViaCallBack (BufferAsStreamCallBack,
- &BufferAsStream, AmountReadPntr, RecycleMe);
- }
-
-
-
- /****** intoids.library/IntoidToPortableIntViaCallBack **********************
- *
- * NAME
- * IntoidToPortableIntViaCallBack -- Converts Intoid to portable int.
- *
- * SYNOPSIS
- * Success = IntoidToPortableIntViaCallBack
- * ( AnIntoid, BytesWrittenPntr, CallBack, UserPntr)
- * D0 D0 A0 D1 A1
- *
- * BOOL IntoidToPortableIntViaCallBack
- * ( Intoid, ULONG *, PortIntCallBackPntr, APTR );
- *
- * FUNCTION
- * Writes the AGMS Portable Integer binary format equivalent of the
- * Intoid to a stream using a callback function. Also tests to see if
- * your compiler can handle 30 letter function names :-).
- *
- * INPUTS
- * AnIntoid - the Intoid big integer to be converted.
- * BytesWrittenPntr - points to a ULONG that will be set to the number
- * of bytes written, specify NULL if you aren't using this feature.
- * CallBack - a user provided function that handles the input
- * stream, see the intoids.library/AGMSPortableIntStreamCallBack
- * entry in these autodocs for details.
- * UserPntr - Any pointer sized value you want. This value will be
- * passed to your callback function. Typically used for file
- * handles.
- *
- * RESULT
- * Success - returns TRUE (1) if successful, FALSE (0) if it fails.
- * BytesWrittenPntr - the pointed to ULONG is set to the number of
- * bytes actually written. If you have an IO error then this
- * will be less than the actual size (see PortableIntSizeOfIntoid())
- * for the number.
- *
- * SEE ALSO
- * PortableIntSizeOfIntoid(), IntoidToPortableIntViaBuffer(),
- * AGMSPortableIntStreamCallBack.
- *
- *****************************************************************************
- */
-
- BOOL LIBFUNC IntoidToPortableIntViaCallBack (
- REGD0 Intoid AnIntoid,
- REGA0 ULONG *BytesWrittenPntr,
- REGD1 PortIntCallBackPntr CallBack,
- REGA1 APTR UserPntr)
- {
- ULONG AmountToWrite;
- ULONG AmountWritten;
- IntRepPointer AnIntRep;
- UBYTE ByteArray[8]; /* Even size, FirstByte + size extension */
- ULONG ByteCount;
- ULONG BytesNeeded;
- unsigned short CurrentShort;
- LONG LongValue;
- unsigned short *NextShortPntr;
- BOOL Negative;
- BOOL ReturnCode;
- IntoidSpecialCodes SpecialCode;
- LONG TempLong;
-
- ByteCount = 0;
- ReturnCode = FALSE;
-
- if (IntoidIsSmallInt (AnIntoid))
- {
- LongValue = IntoidToSmallInt (AnIntoid);
- if (-106 <= LongValue && LongValue <= 127)
- {
- /* This integer can be represented as a single byte. */
-
- ByteArray [0] = (UBYTE) LongValue;
- AmountToWrite = 1;
- }
- else /* Doesn't fit directly in a byte, need a variable length type. */
- {
- TempLong = (Negative = (LongValue < 0)) ? -LongValue : LongValue;
- BytesNeeded = 0;
- while (TempLong)
- {
- ByteArray [BytesNeeded + 1] = (UBYTE) TempLong;
- BytesNeeded++;
- TempLong >>= 8;
- }
- ByteArray [0] = (Negative ? 0x87 : 0x7F) + BytesNeeded;
- AmountToWrite = BytesNeeded + 1;
- }
-
- /* Write the encoded number in ByteArray. */
-
- AmountWritten = (* CallBack) (PICBOP_WRITE, ByteArray, AmountToWrite,
- UserPntr);
- ByteCount += AmountWritten;
- if (AmountWritten != AmountToWrite)
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
- else /* Success */
- ReturnCode = TRUE;
- }
- else if (IntoidIsIntRep (AnIntoid))
- {
- AnIntRep = (IntoidAsPointer) AnIntoid;
-
- if (AnIntRep->currentLength <= 0) /* Shouldn't happen, but... */
- {
- ByteArray [0] = 0; /* Code for small integer zero. */
- AmountToWrite = 1; /* Size of header to write. */
- BytesNeeded = 0; /* Number of body data bytes to write. */
- }
- else /* Have some data to write. How much? */
- {
- BytesNeeded = AnIntRep->currentLength * 2;
- if (AnIntRep->numberArray [AnIntRep->currentLength - 1] < 256)
- --BytesNeeded; /* High byte of high word is zero. */
-
- if (BytesNeeded <= 8) /* Fits in 1 to 8 bytes special code? */
- {
- ByteArray [0] = (AnIntRep->positiveSign ? 0x7F : 0x87) + BytesNeeded;
- AmountToWrite = 1;
- }
- else /* Have lots of bytes to write, need size extension. */
- {
- ByteArray [0] = (AnIntRep->positiveSign ? 0x90 : 0x91);
-
- if (BytesNeeded < 0xFF) /* Fits in a byte? 0xFF used for extension. */
- {
- ByteArray [1] = (UBYTE) BytesNeeded;
- AmountToWrite = 2;
- }
- else if (BytesNeeded < 0xFFFF) /* Fits in 2 bytes? */
- {
- ByteArray [1] = 0xFF; /* Marks doubling of size extension. */
- ByteArray [2] = (UBYTE) BytesNeeded;
- ByteArray [3] = (UBYTE) (BytesNeeded >> 8);
- AmountToWrite = 4;
- }
- else /* Has to fit in 4 bytes. */
- {
- ByteArray [1] = 0xFF; /* Marks doubling of size extension. */
- ByteArray [2] = 0xFF; /* Marks redoubling of size extension. */
- ByteArray [3] = 0xFF;
- ByteArray [4] = (UBYTE) (BytesNeeded);
- ByteArray [5] = (UBYTE) (BytesNeeded >> 8);
- ByteArray [6] = (UBYTE) (BytesNeeded >> 16);
- ByteArray [7] = (UBYTE) (BytesNeeded >> 24);
- AmountToWrite = 8;
- }
- }
- }
-
- /* Write the header fields for the IntRep based number. */
-
- AmountWritten = (* CallBack) (PICBOP_WRITE,
- ByteArray, AmountToWrite, UserPntr);
- ByteCount += AmountWritten;
- if (AmountWritten != AmountToWrite)
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
- else /* Write the body, the actual data bytes. */
- {
- ReturnCode = TRUE; /* Assume success, errors now clear return code. */
-
- #if _M68000 /* Motorola 68000 series CPUs uses MSB order. */
-
- /* Write out the body, swapping low and high bytes in each short.
- Use the ByteArray to buffer things a bit (assumes even size). */
-
- AmountToWrite = 0;
- NextShortPntr = AnIntRep->numberArray;
- while (BytesNeeded > 0)
- {
- CurrentShort = *NextShortPntr++;
- ByteArray [AmountToWrite++] = (UBYTE) CurrentShort;
- if (--BytesNeeded > 0)
- {
- ByteArray [AmountToWrite++] = (UBYTE) (CurrentShort >> 8);
- --BytesNeeded;
- }
-
- if (AmountToWrite >= sizeof (ByteArray) || BytesNeeded == 0)
- {
- AmountWritten = (* CallBack) (PICBOP_WRITE,
- ByteArray, AmountToWrite, UserPntr);
- ByteCount += AmountWritten;
- if (AmountWritten != AmountToWrite)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
- ReturnCode = FALSE;
- break;
- }
- AmountToWrite = 0;
- }
- }
-
- #else /* Just dump the data out directly, already in right byte order. */
-
- if ((AmountToWrite = BytesNeeded) > 0)
- {
- AmountWritten = (* CallBack) (PICBOP_WRITE,
- AnIntRep->numberArray, AmountToWrite, UserPntr);
- ByteCount += AmountWritten;
- if (AmountWritten != AmountToWrite)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
- ReturnCode = FALSE;
- }
- }
- #endif
- }
- }
- else /* Special code or NULL. */
- {
- AmountToWrite = 1;
- SpecialCode = IntoidToSpecialCode (AnIntoid);
- switch (SpecialCode)
- {
- case ISC_NOT_A_NUMBER:
- ByteArray [0] = 0x95;
- break;
-
- case ISC_POSITIVE_INFINITY:
- ByteArray [0] = 0x93;
- break;
-
- case ISC_NEGATIVE_INFINITY:
- ByteArray [0] = 0x94;
- break;
-
- default:
- ByteArray [0] = 0x92; /* Extended special code. */
- ByteArray [1] = 4; /* Noisy not-a-number. */
- AmountToWrite = 2;
- break;
- }
- AmountWritten = (* CallBack) (PICBOP_WRITE, ByteArray, AmountToWrite,
- UserPntr);
- ByteCount += AmountWritten;
- if (AmountWritten != AmountToWrite)
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
- else /* Success */
- ReturnCode = TRUE;
- }
-
- /* Set return values. */
-
- if (BytesWrittenPntr != NULL)
- *BytesWrittenPntr = ByteCount;
-
- return ReturnCode;
- }
-
-
-
- /****** intoids.library/IntoidToPortableIntViaBuffer ************************
- *
- * NAME
- * IntoidToPortableIntViaBuffer -- Converts Intoid to portable int.
- *
- * SYNOPSIS
- * Success = IntoidToPortableIntViaBuffer
- * ( AnIntoid, BytesWrittenPntr, Buffer, BufferSize )
- * D0 D0 A0 A1 D1
- *
- * BOOL IntoidToPortableIntViaBuffer( Intoid, ULONG *, APTR, ULONG );
- *
- * FUNCTION
- * Writes the AGMS Portable Integer binary format equivalent of the
- * Intoid (big integer) to a buffer.
- *
- * INPUTS
- * AnIntoid - the arbitrarily big integer to be converted.
- * BytesWrittenPntr - points to a ULONG that will be set to the number
- * of bytes written, specify NULL if you aren't using this feature.
- * Buffer - points to an area of memory where the portable integer will
- * be written to.
- * BufferSize - amount of space in the buffer. Has to be at least
- * enough for the entire portable integer, or you get a partial
- * portable integer in the buffer and BytesWritten equal to
- * BufferSize.
- *
- * RESULT
- * Success - returns TRUE (1) if successful, FALSE (0) if it fails.
- * BytesWrittenPntr - the pointed to ULONG is set to the number of
- * bytes actually written. If you have an IO error then this
- * will be less than the actual size (see PortableIntSizeOfIntoid())
- * for the number.
- *
- * SEE ALSO
- * PortableIntSizeOfIntoid(), IntoidToPortableIntViaCallBack().
- *
- *****************************************************************************
- */
-
- BOOL LIBFUNC IntoidToPortableIntViaBuffer (
- REGD0 Intoid AnIntoid,
- REGA0 ULONG *BytesWrittenPntr,
- REGA1 APTR Buffer,
- REGD1 ULONG BufferSize)
- {
- BufferStreamRecord BufferAsStream;
-
- BufferAsStream.current = BufferAsStream.start = Buffer;
- BufferAsStream.end = (UBYTE *) Buffer + BufferSize;
-
- return IntoidToPortableIntViaCallBack (AnIntoid, BytesWrittenPntr,
- BufferAsStreamCallBack, &BufferAsStream);
- }
-
-
-
- /******************************************************************************
- * This callback function does nothing, always succeeding in reading or
- * writing or seeking. It is used for finding the size of an Intoid as a
- * portable integer by writing the portable integer to nowhere.
- */
-
- LONG STACKCALL DoNothingStreamCallBack (ULONG Operation, APTR Buffer,
- LONG Amount, APTR UserPntr)
- {
- switch (Operation)
- {
- case PICBOP_READ:
- return Amount;
-
- case PICBOP_SEEK:
- return 0; /* New seek position is always zero. */
-
- case PICBOP_WRITE:
- return Amount;
- }
-
- return -2; /* Unimplemented operation. */
- }
-
-
-
- /****** intoids.library/PortableIntSizeOfIntoid *****************************
- *
- * NAME
- * PortableIntSizeOfIntoid -- Find Intoid size in portable int format.
- *
- * SYNOPSIS
- * Length = PortableIntSizeOfIntoid( AnIntoid )
- * D0 D0
- *
- * ULONG PortableIntSizeOfIntoid( Intoid );
- *
- * FUNCTION
- * Finds the byte size of an Intoid when expressed in AGMS Portable
- * Integer format.
- *
- * INPUTS
- * AnIntoid - the big integer you want to find the formatted size of.
- *
- * RESULT
- * Length - the number of bytes it would take for the AGMS Portable
- * Integer binary format equivalent of AnIntoid.
- *
- *****************************************************************************
- */
-
- ULONG LIBFUNC PortableIntSizeOfIntoid (REGA0 Intoid AnIntoid)
- {
- ULONG ByteCount;
-
- IntoidToPortableIntViaCallBack (AnIntoid, &ByteCount,
- DoNothingStreamCallBack, NULL);
-
- return ByteCount;
- }
-
-
-
- /****** intoids.library/IntoidToAscii ***************************************
- *
- * NAME
- * IntoidToAscii -- Converts an Intoid into printable ASCII text.
- *
- * SYNOPSIS
- * RequiredLength = IntoidToAscii( IntegerA, Buffer, BufferLength, Base)
- * D0 A0 A1 D0 D1
- *
- * LONG IntoidToAscii( Intoid, STRPTR, LONG, UWORD );
- *
- * FUNCTION
- * Converts the Intoid to a readable string number in the given base.
- * Also can output special strings for not-a-number and infinities, and
- * various error messages if something goes wrong during the conversion.
- *
- * INPUTS
- * IntegerA - any Intoid.
- * Buffer - points to a user provided buffer that will be filled with
- * the NUL terminated string ASCII text equivalent of IntegerA.
- * This variable can be NULL (useful if you just want an estimate of
- * how long the string would be).
- * BufferLength - how many bytes are in Buffer. Can be zero.
- * Base - what number system to use for the conversion. Can be from 2
- * to 36 (because it uses the 26 lower case letters and '0' to '9'
- * for the output digits).
- *
- * RESULT
- * RequiredLength - returns the number of characters plus one (for the
- * NUL at the end of the string) required to represent the number
- * (may be more than BufferLength).
- * Buffer - filled with the number, or with '*' characters if it isn't
- * big enough to hold the number.
- *
- * NOTES
- * Uses about 1K of the caller's stack space.
- *
- * BUGS
- * Numbers can only be converted if they are less than
- * MAX_INTOID_ASCII_DIGITS long. This is because a reversed number is
- * built up in a buffer this big on the caller's stack (thus you need
- * about 1K of stack when calling this function). If a number is too
- * big, you will get an error message instead of the number.
- *
- *****************************************************************************
- */
-
- LONG LIBFUNC IntoidToAscii (REGA0 Intoid IntegerA, REGA1 STRPTR Buffer,
- REGD0 LONG BufferLength, REGD1 UWORD Base)
- {
- char *NextDigitPntr;
- BOOL Positive;
- long RequiredLength;
- char ReversedNumber [MAX_INTOID_ASCII_DIGITS];
- char *EndOfReversedNumber;
-
- if (Base < 2 || Base > 36)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- return 0; /* Avoid infinite loops and divide by zero and bad characters. */
- }
-
- if (Buffer == NULL)
- BufferLength = 0; /* Fine, we will just tell them how many digits. */
-
- NextDigitPntr = ReversedNumber;
- EndOfReversedNumber = ReversedNumber + sizeof (ReversedNumber);
- Positive = TRUE;
-
- if (IntoidIsSmallInt (IntegerA))
- {
- unsigned long rem;
- long SmallInt = IntoidToSmallInt (IntegerA);
- if (SmallInt < 0)
- {
- SmallInt = -SmallInt;
- Positive = FALSE;
- }
- rem = SmallInt;
- while (rem != 0)
- {
- char ch;
- #if _AMIGA && __SASC
- rem = UDivMod32 (rem, (unsigned long) Base);
- ch = getreg (REG_D1);
- #else
- ch = rem % Base;
- rem /= Base;
- #endif
- if (ch >= 10)
- ch += 'a' - 10;
- else
- ch += '0';
- *NextDigitPntr++ = ch;
- }
- }
- else if (IntoidIsIntRep (IntegerA))
- {
- IntRepPointer IntRepA = (IntoidAsPointer) IntegerA;
- IntRepPointer TempIntRep;
- TempIntRep = Icopy (NULL, IntRepA);
- if (TempIntRep == NULL)
- {
- strcpy (ReversedNumber,
- GetIntoidsMessage (MSG_INTOIDS_PRINTING_OUT_OF_MEMORY));
- strrev (ReversedNumber);
- NextDigitPntr = ReversedNumber + strlen (ReversedNumber);
- }
- else /* Not out of memory. */
- {
- /* split division by base into two parts:
- first divide by biggest power of base that fits in an unsigned short,
- then use straight signed div/mods from there. */
-
- /* find power */
- int bpower = 1;
- unsigned short b = Base;
- unsigned short maxb = I_MAXNUM / Base;
- while (b < maxb)
- {
- b *= Base;
- ++bpower;
- }
-
- Positive = IntRepA->positiveSign;
- for(;;)
- {
- unsigned short rem = unscale(TempIntRep->numberArray,
- TempIntRep->currentLength, b, TempIntRep->numberArray);
- Icheck(TempIntRep);
- if (TempIntRep->currentLength == 0)
- {
- while (rem != 0)
- {
- char ch;
- unsigned short u;
- u = rem / Base;
- ch = rem - u * Base;
- rem = u;
- if (ch >= 10)
- ch += 'a' - 10;
- else
- ch += '0';
- if (NextDigitPntr < EndOfReversedNumber)
- *NextDigitPntr = ch;
- ++NextDigitPntr;
- }
- Idelete (TempIntRep);
- break;
- }
- else
- {
- int i;
- for (i = 0; i < bpower; ++i)
- {
- char ch;
- unsigned short u;
- u = rem / Base;
- ch = rem - u * Base;
- rem = u;
- if (ch >= 10)
- ch += 'a' - 10;
- else
- ch += '0';
- if (NextDigitPntr < EndOfReversedNumber)
- *NextDigitPntr = ch;
- ++NextDigitPntr;
- }
- }
- }
- }
- }
- else /* Must be a specially encoded meaning. */
- {
- switch (IntoidToSpecialCode (IntegerA))
- {
- case ISC_NEGATIVE_INFINITY:
- Positive = FALSE;
- case ISC_POSITIVE_INFINITY:
- strcpy (ReversedNumber, GetIntoidsMessage (MSG_INTOIDS_INFINITY));
- break;
-
- case ISC_NOT_A_NUMBER:
- default:
- strcpy (ReversedNumber, GetIntoidsMessage (MSG_INTOIDS_NOT_A_NUMBER));
- break;
- }
- strrev (ReversedNumber);
- NextDigitPntr = ReversedNumber + strlen (ReversedNumber);
- }
-
- if (NextDigitPntr == ReversedNumber)
- *NextDigitPntr++ = '0'; /* Empty string means zero. */
-
- if (NextDigitPntr > EndOfReversedNumber)
- {
- strcpy (ReversedNumber,
- GetIntoidsMessage (MSG_INTOIDS_NUMBER_TOO_BIG_TO_PRINT));
- strrev (ReversedNumber);
- NextDigitPntr = ReversedNumber + strlen (ReversedNumber);
- }
-
- /* Now have the number's digits. Find out if there is space for it. */
-
- RequiredLength = (NextDigitPntr - ReversedNumber) + 1 /* For NUL */;
- if (!Positive) RequiredLength++;
-
- if (RequiredLength > BufferLength)
- {
- /* Number too big, fill buffer with '*' characters. */
-
- while (BufferLength > 1)
- {
- *Buffer++ = '*';
- --BufferLength;
- }
- }
- else
- {
- /* Reverse copy the string to the output buffer. Put the minus sign in
- front if it is negative. */
-
- if (!Positive)
- *Buffer++ = '-';
-
- /* Copy the digits (or error message) over. */
-
- while (--NextDigitPntr >= ReversedNumber)
- *Buffer++ = *NextDigitPntr;
- }
-
- if (BufferLength > 0)
- *Buffer = 0; /* End of string. */
-
- return RequiredLength;
- }
-
-
-
- /****** intoids.library/AsciiToIntoid ***************************************
- *
- * NAME
- * AsciiToIntoid -- Convert an ASCII string to an Intoid.
- *
- * SYNOPSIS
- * New = AsciiToIntoid( Buffer, NextCharacterPntrPntr, Base, RecycleMe )
- * D0 A0 A1 D0 D1
- *
- * Intoid AsciiToIntoid( STRPTR, char **, UWORD, Intoid );
- *
- * FUNCTION
- * Converts a string to a number using the given base, much like
- * the standard C function strtol. It recognizes numbers consisting of
- * some leading space ((spaces or tabs) or international isspace() if
- * locale.library is available), an optional sign, an optional base
- * indicator if Base is zero, and finally a bunch of digits (which can
- * also be the special current language specific strings for infinity or
- * not-a-number).
- *
- * INPUTS
- * Buffer - points to a buffer containing the NUL terminated string to
- * be converted.
- * NextCharacterPntrPntr - points to a user's pointer variable, or NULL
- * if you don't want to use it. The user's pointer variable will be
- * set to point to the character after the last one that was part of
- * the number (or set to NULL if a bad error happened).
- * Base - which number system to use. Base can be from 2 to 36. A Base
- * of 0 can be used for automatic base determination (if the number
- * starts with "0x" then it is treated as base 16, if it starts with
- * "0" then base 8 is used, otherwise it defaults to base 10).
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * New - a newly allocated Intoid with the integer equivalent to the
- * string in Buffer. NULL if out of memory or some other error
- * happens (or if the string says not-a-number).
- * NextCharacterPntrPntr - sets user's pointer to just after the number.
- *
- * NOTES
- * The special strings for infinity and not-a-number are language
- * dependent. If you read a file written in English on a French
- * computer, it won't understand the special infinity values. Instead,
- * you should use the portable binary formatting functions.
- *
- * SEE ALSO
- * GetIntoidsMessage(), MSG_INTOIDS_NOT_A_NUMBER, MSG_INTOIDS_INFINITY.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC AsciiToIntoid (REGA0 STRPTR Buffer,
- REGA1 char **NextCharacterPntrPntr, REGD0 UWORD Base,
- REGD1 Intoid RecycleMe)
- {
- const char *CharPntr;
- char Digit;
- const char *DigitsStart;
- char Letter;
- int Log2OfBase;
- unsigned long NewLength;
- const char *NumberEnd;
- const char *NumberStart;
- BOOL IsPositive;
- Intoid ReturnValue;
- long TempLong;
-
- if (NextCharacterPntrPntr != NULL)
- *NextCharacterPntrPntr = NULL; /* In case of errors. */
-
- if (Buffer == NULL || Base == 1 || Base > 36)
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
- return NULL; /* Can't do it. */
- }
-
- /* Skip leading space to get to the start of
- the number (may be a sign or digit). */
-
- NumberEnd = NULL; /* This only gets set when we have an answer. */
- NumberStart = Buffer;
- while (MyIsSpace ((unsigned long) *NumberStart))
- ++NumberStart;
-
- /* Go past the sign to get to the digits. */
-
- IsPositive = TRUE;
- DigitsStart = NumberStart;
- if (*DigitsStart == '-')
- {
- ++DigitsStart;
- IsPositive = FALSE;
- }
- else if (*DigitsStart == '+')
- ++DigitsStart;
-
- /* Check for magic base indicators, only if Base is zero. */
-
- if (Base == 0)
- {
- if (*DigitsStart == '0') /* Number starts with a leading zero. */
- {
- ++DigitsStart; /* Skip leading zero. */
- if (*DigitsStart == 'x' || *DigitsStart == 'X')
- {
- Base = 16;
- ++DigitsStart; /* Skip over the x. */
- }
- else
- Base = 8;
- }
- else /* The default base. */
- Base = 10;
- }
-
- /* Check for infinity or not a number strings. Use the utility.library
- international string comparison functions. */
-
- CharPntr = GetIntoidsMessage (MSG_INTOIDS_NOT_A_NUMBER);
- if (Strnicmp ((STRPTR) CharPntr, (STRPTR) DigitsStart,
- (long) strlen (CharPntr)) == 0)
- {
- NumberEnd = DigitsStart + strlen (CharPntr);
- ReturnValue = NULL; /* Not a number. */
- }
- else
- {
- CharPntr = GetIntoidsMessage (MSG_INTOIDS_INFINITY);
- if (Strnicmp ((STRPTR) CharPntr, (STRPTR) DigitsStart,
- (long) strlen (CharPntr)) == 0)
- {
- NumberEnd = DigitsStart + strlen (CharPntr);
- if (IsPositive)
- ReturnValue = SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- else
- ReturnValue = SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- }
- }
-
- if (NumberEnd == NULL)
- {
- /* Find number of bits in the base, each digit in the
- input can have at most this many bits in the number. */
-
- Log2OfBase = 0;
- TempLong = Base;
- while (TempLong != 0)
- {
- TempLong >>= 1;
- Log2OfBase++;
- }
-
- /* Find the end of the number, and count digits. */
-
- CharPntr = DigitsStart;
- while ((Letter = *CharPntr) != 0)
- {
- if (Letter >= '0' && Letter <= '9') Digit = Letter - '0';
- else if (Letter >= 'a' && Letter <= 'z') Digit = Letter - 'a' + 10;
- else if (Letter >= 'A' && Letter <= 'Z') Digit = Letter - 'A' + 10;
- else break;
- if (Digit >= Base) break;
- ++CharPntr;
- }
- NumberEnd = CharPntr;
-
- /* Now find the total number of bits that we might need. The actual
- number may be smaller if there are leading zeroes. */
-
- NewLength = (NumberEnd - DigitsStart) * (long) Log2OfBase;
-
- /* If it doesn't fit in a small integer Intoid... */
-
- if (NewLength > CHAR_PER_LONG * CHAR_BIT - 2)
- {
- /* May need a full IntRep, allocate one then reduce later. */
-
- NewLength = NewLength / I_SHIFT + 1; /* Number of shorts we need. */
- ReturnValue = ResizeIntoid (RecycleMe, NewLength, TRUE /* Zero it */);
- RecycleMe = NULL; /* We have used it. */
-
- /* Reading in a large number into an IntRep. Stop when an error
- happens or if it already happened (out of memory). */
-
- CharPntr = DigitsStart;
- while ((Letter = *CharPntr) != 0 && ReturnValue != NULL)
- {
- if (Letter >= '0' && Letter <= '9') Digit = Letter - '0';
- else if (Letter >= 'a' && Letter <= 'z') Digit = Letter - 'a' + 10;
- else if (Letter >= 'A' && Letter <= 'Z') Digit = Letter - 'A' + 10;
- else break;
- if (Digit >= Base) break;
-
- ReturnValue = MultiplyLongAndIntRep ((long) Base, ReturnValue,
- ReturnValue);
-
- ReturnValue = AddLongAndIntRep ((long) Digit, ReturnValue,
- FALSE /* don't negate it */, ReturnValue);
-
- ++CharPntr;
- }
- if (IntoidIsIntRep (ReturnValue))
- {
- ((IntoidAsPointer) ReturnValue)->positiveSign = IsPositive;
- ReturnValue = NormalizeIntoid (ReturnValue);
- }
- else /* Something went wrong. Probably out of memory. */
- {
- FreeIntoid (ReturnValue);
- ReturnValue = NULL;
- }
- }
- else /* Number will fit in a small integer intoid. */
- {
- TempLong = 0;
- CharPntr = DigitsStart;
- while ((Letter = *CharPntr) != 0)
- {
- if (Letter >= '0' && Letter <= '9') Digit = Letter - '0';
- else if (Letter >= 'a' && Letter <= 'z') Digit = Letter - 'a' + 10;
- else if (Letter >= 'A' && Letter <= 'Z') Digit = Letter - 'A' + 10;
- else break;
- if (Digit >= Base) break;
- TempLong = TempLong * Base + Digit;
- ++CharPntr;
- }
- if (!IsPositive)
- TempLong = -TempLong;
- ReturnValue = SmallIntToIntoid (TempLong);
- }
- }
-
- FreeIntoid (RecycleMe); /* Frees it if it wasn't used up. */
-
- if (NextCharacterPntrPntr != NULL)
- *NextCharacterPntrPntr = (char *) NumberEnd;
-
- return ReturnValue;
- }
-
-
-
- /****** intoids.library/CopyIntoid ******************************************
- *
- * NAME
- * CopyIntoid -- Allocates a copy of an Intoid.
- *
- * SYNOPSIS
- * NewIntoid = CopyIntoid( IntegerA, RecycleMe )
- * D0 D0 D1
- *
- * Intoid CopyIntoid( Intoid, Intoid );
- *
- * FUNCTION
- * Allocates memory (if needed) and fills it with a copy of IntegerA.
- *
- * INPUTS
- * IntegerA - the Integer value you want to copy.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - A copy of IntegerA or NULL if out of memory.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC CopyIntoid (REGD0 Intoid IntegerA, REGD1 Intoid RecycleMe)
- {
- Intoid NewIntoid;
- IntRepPointer NewRep;
-
- if (IntoidIsIntRep (IntegerA))
- {
- NewRep = Icopy (IntoidIsIntRep (RecycleMe) ?
- (IntoidAsPointer) RecycleMe : NULL,
- (IntoidAsPointer) IntegerA);
-
- if (NewRep != NULL)
- Icheck (NewRep);
-
- NewIntoid = NormalizeIntoid ((Intoid) NewRep);
- }
- else /* A small integer or special code. No auxiliary data. */
- {
- NewIntoid = IntegerA;
- FreeIntoid (RecycleMe);
- }
-
- return NewIntoid;
- }
-
-
-
- /****** intoids.library/AddIntoids ******************************************
- *
- * NAME
- * AddIntoids -- Adds two Intoids.
- *
- * SYNOPSIS
- * NewIntoid = AddIntoids( IntegerA, IntegerB, RecycleMe )
- * D0 D0 D1 A0
- *
- * Intoid AddIntoids( Intoid, Intoid, Intoid );
- *
- * FUNCTION
- * Adds two intoids and returns a new one with the sum.
- *
- * INPUTS
- * IntegerA - one value to be added.
- * IntegerB - the other value to be added.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - newly allocated Intoid with a value of (A + B), or NULL
- * if out of memory.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC AddIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
- REGA0 Intoid RecycleMe)
- {
- /* Most frequent case is two small integer Intoids. Just convert to longs
- and add. They shouldn't overflow in the long addition, though the result
- may be too big for a small integer (LongToIntoid will fix that). */
-
- if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
- return LongToIntoid (IntoidToSmallInt (IntegerA) +
- IntoidToSmallInt (IntegerB), RecycleMe);
-
- /* If adding zero or not-a-number, return a copy of the other number. */
-
- if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0))
- return CopyIntoid (IntegerB, RecycleMe);
-
- if (IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
- return CopyIntoid (IntegerA, RecycleMe);
-
- /* Check for adding infinity. The result is usually infinity. */
-
- if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- return SmallIntToIntoid (0); /* Well... */
- return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- }
-
- if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- return SmallIntToIntoid (0); /* Well... */
- return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- }
-
- if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- return SmallIntToIntoid (0); /* Well... */
- return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- }
-
- if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- return SmallIntToIntoid (0); /* Well... */
- return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- }
-
- if (IntoidIsSpecialCode (IntegerA))
- {
- FreeIntoid (RecycleMe);
- return IntegerA;
- }
-
- if (IntoidIsSpecialCode (IntegerB))
- {
- FreeIntoid (RecycleMe);
- return IntegerB;
- }
-
- /* Check for numbers that fit in a long so we can do a simpler long/intrep
- addition. Already know that not both are small integers. */
-
- if (IntoidIsSmallInt (IntegerA))
- return NormalizeIntoid (AddLongAndIntRep (IntoidToSmallInt (IntegerA),
- IntegerB, FALSE, RecycleMe));
-
- if (IntoidIsSmallInt (IntegerB))
- return NormalizeIntoid (AddLongAndIntRep (IntoidToSmallInt (IntegerB),
- IntegerA, FALSE, RecycleMe));
-
- /* Ok, now adding two Intoids which are IntReps. */
-
- return NormalizeIntoid (AddIntRepAndIntRep (IntegerA, FALSE,
- IntegerB, FALSE, RecycleMe));
- }
-
-
-
- /****** intoids.library/NegateIntoid ****************************************
- *
- * NAME
- * NegateIntoid -- Returns the negative of an intoid.
- *
- * SYNOPSIS
- * NewIntoid = NegateIntoid( IntegerA, RecycleMe )
- * D0 D0 D1
- *
- * Intoid NegateIntoid( Intoid, Intoid );
- *
- * FUNCTION
- * Computes (0 - IntegerA).
- *
- * INPUTS
- * IntegerA - the value you want to get the negative of.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - newly allocated Intoid containing (0 - IntegerA), or NULL
- * if out of memory.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC NegateIntoid (REGD0 Intoid IntegerA, REGD1 Intoid RecycleMe)
- {
- Intoid Negated;
- IntRepPointer NegatedRep;
-
- Negated = CopyIntoid (IntegerA, RecycleMe);
-
- if (IntoidIsSmallInt (Negated))
- {
- Negated = LongToIntoid (-IntoidToSmallInt (Negated), NULL);
- }
- else if (IntoidIsIntRep (Negated))
- {
- NegatedRep = (IntoidAsPointer) Negated;
- NegatedRep->positiveSign = !NegatedRep->positiveSign;
- /* Don't bother converting -0x40000000 to small integer form. */
- }
- else /* A special code. Only infinities change sign. */
- {
- if (Negated == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- Negated = SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- else if (Negated == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- Negated = SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- }
-
- return Negated;
- }
-
-
-
- /****** intoids.library/AbsoluteIntoid **************************************
- *
- * NAME
- * AbsoluteIntoid -- Computes absolute value of an Intoid.
- *
- * SYNOPSIS
- * NewIntoid = AbsoluteIntoid( IntegerA, RecycleMe )
- * D0 D0 D1
- *
- * Intoid AbsoluteIntoid( Intoid, Intoid );
- *
- * FUNCTION
- * Computes the absolute value of an Intoid.
- *
- * INPUTS
- * IntegerA - the value you want to get the negative of.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - newly allocated Intoid containing a copy of IntegerA if
- * IntegerA was positive, or the negative of IntegerA if it was
- * originally negative (the negative of a negative is positive), or
- * NULL if out of memory.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC AbsoluteIntoid (REGD0 Intoid IntegerA,
- REGD1 Intoid RecycleMe)
- {
- if (SignOfIntoid (IntegerA) < 0)
- return NegateIntoid (IntegerA, RecycleMe);
-
- return CopyIntoid (IntegerA, RecycleMe);
- }
-
-
-
- /****** intoids.library/SubtractIntoids *************************************
- *
- * NAME
- * SubtractIntoids -- Computes value of one Intoid minus another.
- *
- * SYNOPSIS
- * NewIntoid = SubtractIntoids( IntegerA, IntegerB, RecycleMe )
- * D0 D0 D1 A0
- *
- * Intoid SubtractIntoids( Intoid, Intoid, Intoid );
- *
- * FUNCTION
- * Does subtraction, IntegerA - IntegerB.
- *
- * INPUTS
- * IntegerA - one input value.
- * IntegerB - the other input value.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - newly allocated Intoid containing the value of
- * (IntegerA - IntegerB), or NULL if out of memory.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC SubtractIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
- REGA0 Intoid RecycleMe)
- {
- /* Most frequent case is two small integer Intoids. Just convert to longs
- and subtract. They shouldn't overflow in the long addition, though the
- result may be too big for a small integer (LongToIntoid will fix that). */
-
- if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
- return LongToIntoid (IntoidToSmallInt (IntegerA) -
- IntoidToSmallInt (IntegerB), RecycleMe);
-
- /* If subtracting zero or not-a-number, return a copy of the other number,
- or a negative of it. */
-
- if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0))
- return NegateIntoid (IntegerB, RecycleMe);
-
- if (IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
- return CopyIntoid (IntegerA, RecycleMe);
-
- /* Check for subtracting infinity. The result is usually infinity
- except when subtracting the same infinity, which has a zero
- result even though that probably isn't meaningful. */
-
- if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- return SmallIntToIntoid (0);
- return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- }
-
- if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
- return SmallIntToIntoid (0);
- return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- }
-
- if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- return SmallIntToIntoid (0);
- return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- }
-
- if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- {
- FreeIntoid (RecycleMe);
- if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- return SmallIntToIntoid (0);
- return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- }
-
- if (IntoidIsSpecialCode (IntegerA))
- {
- FreeIntoid (RecycleMe);
- return IntegerA;
- }
-
- if (IntoidIsSpecialCode (IntegerB))
- {
- FreeIntoid (RecycleMe);
- return IntegerB;
- }
-
- /* Check for numbers that fit in a long so we can do a simpler long/intrep
- addition. Already know that not both are small integers. */
-
- if (IntoidIsSmallInt (IntegerA))
- return NormalizeIntoid (AddLongAndIntRep (IntoidToSmallInt (IntegerA),
- IntegerB, TRUE /* negate it */, RecycleMe));
-
- if (IntoidIsSmallInt (IntegerB))
- return NormalizeIntoid (AddLongAndIntRep (-IntoidToSmallInt (IntegerB),
- IntegerA, FALSE, RecycleMe));
-
- /* Ok, now adding two Intoids which are IntReps. */
-
- return NormalizeIntoid (AddIntRepAndIntRep (IntegerA, FALSE,
- IntegerB, TRUE /* negate it */, RecycleMe));
- }
-
-
-
- /****** intoids.library/CompareIntoids **************************************
- *
- * NAME
- * CompareIntoids -- Signed comparison of two Intoid values.
- *
- * SYNOPSIS
- * Result = CompareIntoids( IntegerA, IntegerB )
- * D0 D0 D1
- *
- * LONG CompareIntoids( Intoid, Intoid );
- *
- * FUNCTION
- * Compares the size of two Intoids, more efficiently than using a
- * subtraction.
- *
- * INPUTS
- * IntegerA - one input value.
- * IntegerB - the other input value.
- *
- * RESULT
- * Result - returns a long value that depends on the comparison:
- * -1 for IntegerA < IntegerB,
- * 0 for IntegerA == IntegerB,
- * +1 for IntegerA > IntegerB.
- *
- * SEE ALSO
- * SignOfIntoid(), CompareIntoidMagnitudes().
- *
- *****************************************************************************
- */
-
- LONG LIBFUNC CompareIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB)
- {
- long ComparisonResult;
- Intoid IntegerResult;
- unsigned short LengthA;
- unsigned short LengthB;
- IntRepPointer RepA;
- IntRepPointer RepB;
- BOOL SignA;
- BOOL SignB;
-
- /* Special case speed optimization for two IntRep based Intoids. */
-
- if (IntoidIsIntRep (IntegerA) && IntoidIsIntRep (IntegerB))
- {
- RepA = (IntoidAsPointer) IntegerA;
- RepB = (IntoidAsPointer) IntegerB;
-
- LengthA = RepA->currentLength;
- LengthB = RepB->currentLength;
-
- SignA = RepA->positiveSign;
- SignB = RepB->positiveSign;
-
- ComparisonResult = SignA - SignB; /* Note that signs are 0=neg or 1=pos. */
- if (ComparisonResult == 0) /* Have to do an effective subtraction. */
- {
- /* See which one is bigger, IntegerA or IntegerB. */
-
- ComparisonResult = (long) LengthA - (long) LengthB;
- if (ComparisonResult == 0) /* Same length, compare values. */
- ComparisonResult = CompareNumberArrays (RepA->numberArray,
- RepB->numberArray, LengthA);
-
- if (ComparisonResult < 0) /* If B is bigger in magnitude. */
- ComparisonResult = SignB ? -1L : 1L; /* Were doing A-B, so -B. */
- else if (ComparisonResult > 0) /* If A is bigger in magnitude. */
- ComparisonResult = SignA ? 1L : -1L;
- /* Else equal and ComparisonResult is zero. */
- }
- }
- else /* Small integers or special codes or a mixture of things. */
- {
- IntegerResult = SubtractIntoids (IntegerA, IntegerB, NULL);
- ComparisonResult = IntoidToLong (IntegerResult);
- FreeIntoid (IntegerResult);
- if (ComparisonResult < 0)
- ComparisonResult = -1L;
- else if (ComparisonResult > 0)
- ComparisonResult = 1L;
- }
-
- return ComparisonResult;
- }
-
-
-
- /****** intoids.library/CompareIntoidMagnitudes *****************************
- *
- * NAME
- * CompareIntoidMagnitudes -- Comparison of absolute values.
- *
- * SYNOPSIS
- * Result = CompareIntoidMagnitudes( IntegerA, IntegerB )
- * D0 D0 D1
- *
- * LONG CompareIntoidMagnitudes( Intoid, Intoid );
- *
- * FUNCTION
- * Compares the absolute values of two Intoids, more efficiently than
- * using a subtraction of absolute values.
- *
- * INPUTS
- * IntegerA - one input value.
- * IntegerB - the other input value.
- *
- * RESULT
- * Result - returns a long value that depends on the comparison:
- * -1 for abs(IntegerA) < abs(IntegerB),
- * 0 for abs(IntegerA) == abs(IntegerB),
- * +1 for abs(IntegerA) > abs(IntegerB).
- *
- * SEE ALSO
- * SignOfIntoid(), CompareIntoids().
- *
- *****************************************************************************
- */
-
- LONG LIBFUNC CompareIntoidMagnitudes (REGD0 Intoid IntegerA,
- REGD1 Intoid IntegerB)
- {
- long ComparisonResult;
- Intoid IntegerResult;
- unsigned short LengthA;
- unsigned short LengthB;
- IntRepPointer RepA;
- IntRepPointer RepB;
- Intoid TempA;
- Intoid TempB;
-
- /* Special case speed optimization for two IntRep based Intoids. */
-
- if (IntoidIsIntRep (IntegerA) && IntoidIsIntRep (IntegerB))
- {
- RepA = (IntoidAsPointer) IntegerA;
- RepB = (IntoidAsPointer) IntegerB;
-
- LengthA = RepA->currentLength;
- LengthB = RepB->currentLength;
-
- /* See which one is bigger, IntegerA or IntegerB. */
-
- ComparisonResult = (long) LengthA - (long) LengthB;
- if (ComparisonResult == 0) /* Same length, compare values. */
- ComparisonResult = CompareNumberArrays (RepA->numberArray,
- RepB->numberArray, LengthA);
- }
- else /* Small integers or special codes or a mixture of things. */
- {
- TempA = AbsoluteIntoid (IntegerA, NULL);
- TempB = AbsoluteIntoid (IntegerB, NULL);
- IntegerResult = SubtractIntoids (TempA, TempB, NULL);
- ComparisonResult = IntoidToLong (IntegerResult);
- FreeIntoid (TempA);
- FreeIntoid (TempB);
- FreeIntoid (IntegerResult);
- }
-
- if (ComparisonResult < 0)
- ComparisonResult = -1L;
- else if (ComparisonResult > 0)
- ComparisonResult = 1L;
-
- return ComparisonResult;
- }
-
-
-
- /****** intoids.library/MultiplyIntoids *************************************
- *
- * NAME
- * MultiplyIntoids -- Computes value of one Intoid times another.
- *
- * SYNOPSIS
- * NewIntoid = MultiplyIntoids( IntegerA, IntegerB, RecycleMe )
- * D0 D0 D1 A0
- *
- * Intoid MultiplyIntoids( Intoid, Intoid, Intoid );
- *
- * FUNCTION
- * Does multiplication, IntegerA * IntegerB.
- *
- * INPUTS
- * IntegerA - one input value.
- * IntegerB - the other input value.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - newly allocated Intoid containing the value of
- * (IntegerA * IntegerB), or NULL if out of memory.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC MultiplyIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
- REGA0 Intoid RecycleMe)
- {
- unsigned short BitsA;
- unsigned short BitsB;
- long LongA;
- long LongB;
- Intoid ResultIntoid;
-
- /* If multiplying by zero or not-a-number, return zero. */
-
- if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0) ||
- IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
- {
- FreeIntoid (RecycleMe);
- return SmallIntToIntoid (0);
- }
-
- /* If multiplying by positive 1, return the other argument. */
-
- if (IntegerA == SmallIntToIntoid (1))
- return CopyIntoid (IntegerB, RecycleMe);
- if (IntegerB == SmallIntToIntoid (1))
- return CopyIntoid (IntegerA, RecycleMe);
-
- /* If multiplying by negative 1, return the negated other argument. */
-
- if (IntegerA == SmallIntToIntoid (-1))
- return NegateIntoid (IntegerB, RecycleMe);
- if (IntegerB == SmallIntToIntoid (-1))
- return NegateIntoid (IntegerA, RecycleMe);
-
- /* Check for two small integer Intoids. Just convert to longs and do the
- multiply. If it would overflow then make one of them an IntRep and do
- the multiplication (have to do this after the zero and one tests since
- MultiplyLongAndIntRep doesn't handle all those cases for the IntRep
- argument). */
-
- if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
- {
- LongA = IntoidToSmallInt (IntegerA);
- BitsA = 0;
- if (LongA < 0) LongA = -LongA;
- while (LongA != 0)
- {
- BitsA++;
- LongA >>= 1;
- }
-
- LongB = IntoidToSmallInt (IntegerB);
- BitsB = 0;
- if (LongB < 0) LongB = -LongB;
- while (LongB != 0)
- {
- BitsB++;
- LongB >>= 1;
- }
-
- if (BitsA + BitsB <= CHAR_PER_LONG * CHAR_BIT - 2)
- return LongToIntoid (IntoidToSmallInt (IntegerA) *
- IntoidToSmallInt (IntegerB), RecycleMe);
-
- /* Else result may be too big to fit in a long, so convert one argument to
- an IntRep and do the long vs IntRep multiplication. */
-
- RecycleMe = LongToIntRep (IntoidToSmallInt (IntegerB), RecycleMe);
- if (RecycleMe == NULL)
- ResultIntoid = NULL;
- else
- {
- ResultIntoid = MultiplyLongAndIntRep (IntoidToSmallInt (IntegerA),
- RecycleMe, RecycleMe);
- ResultIntoid = NormalizeIntoid (ResultIntoid);
- }
- return ResultIntoid;
- }
-
- /* Check for multiplying by infinity. The result is infinity. */
-
- if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY) ||
- IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY) ||
- IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY) ||
- IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- {
- LongA = IntoidToLong (IntegerA);
- LongB = IntoidToLong (IntegerB);
- FreeIntoid (RecycleMe);
- if ((LongA < 0) == (LongB < 0))
- return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- else /* Have different signs. */
- return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- }
-
- if (IntoidIsSpecialCode (IntegerA))
- {
- FreeIntoid (RecycleMe);
- return IntegerA;
- }
-
- if (IntoidIsSpecialCode (IntegerB))
- {
- FreeIntoid (RecycleMe);
- return IntegerB;
- }
-
- /* Check for numbers that fit in a long so we can do a simpler long/intrep
- multiplication. Arguments can only be small integers or IntReps at this
- point, and not both small integers. */
-
- if (IntoidIsSmallInt (IntegerA))
- return NormalizeIntoid (MultiplyLongAndIntRep (IntoidToSmallInt (IntegerA),
- IntegerB, RecycleMe));
-
- if (IntoidIsSmallInt (IntegerB))
- return NormalizeIntoid (MultiplyLongAndIntRep (IntoidToSmallInt (IntegerB),
- IntegerA, RecycleMe));
-
- /* Have two IntReps, do the multiplication. */
-
- return NormalizeIntoid (MultiplyIntRepAndIntRep (IntegerA, IntegerB,
- RecycleMe));
- }
-
-
-
- /****** intoids.library/DivideIntoids ***************************************
- *
- * NAME
- * DivideIntoids -- Computes value of one Intoid divided by another.
- *
- * SYNOPSIS
- * NewIntoid = DivideIntoids( IntegerA, IntegerB, RecycleMe )
- * D0 D0 D1 A0
- *
- * Intoid DivideIntoids( Intoid, Intoid, Intoid );
- *
- * FUNCTION
- * Does division, IntegerA / IntegerB.
- *
- * INPUTS
- * IntegerA - one input value.
- * IntegerB - the other input value.
- * RecycleMe - an old Intoid you want to deallocate, or NULL.
- *
- * RESULT
- * NewIntoid - newly allocated Intoid containing the value of
- * (IntegerA / IntegerB), or NULL if out of memory or if
- * you divided by zero.
- *
- *****************************************************************************
- */
-
- Intoid LIBFUNC DivideIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
- REGA0 Intoid RecycleMe)
- {
- long ComparisonResult;
- long LongA;
- long LongB;
-
- /* Check for divide by zero or not-a-number. */
-
- if (IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
- {
- DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_DIVIDE_BY_ZERO));
- FreeIntoid (RecycleMe);
- return NULL;
- }
-
- /* Most frequent case is two small integer Intoids. Just
- convert to longs and do it. Should never overflow. */
-
- if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
- {
- LongA = IntoidToSmallInt (IntegerA);
- LongB = IntoidToSmallInt (IntegerB);
- return LongToIntoid (LongA / LongB, RecycleMe);
- }
-
- /* If numerator is zero or NAN or just less than denominator
- in magnitude, return zero. This also handles the case
- where the divisor is infinity and the numerator is less. */
-
- ComparisonResult = CompareIntoidMagnitudes (IntegerA, IntegerB);
-
- if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0) ||
- ComparisonResult < 0)
- {
- FreeIntoid (RecycleMe);
- return SmallIntToIntoid (0);
- }
-
- /* If the numerator and denominator are equal then return one or -1. */
-
- if (ComparisonResult == 0)
- {
- ComparisonResult =
- (SignOfIntoid (IntegerA) == SignOfIntoid (IntegerB)) ? 1L : -1L;
- FreeIntoid (RecycleMe);
- return SmallIntToIntoid (ComparisonResult);
- }
-
- /* If dividing by one, return the other value. */
-
- if (IntegerB == SmallIntToIntoid (1))
- return CopyIntoid (IntegerA, RecycleMe);
-
- if (IntegerB == SmallIntToIntoid (-1))
- return NegateIntoid (IntegerA, RecycleMe);
-
- /* Check for numerator of infinity. The result is infinity. */
-
- if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY) ||
- IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
- {
- ComparisonResult =
- (SignOfIntoid (IntegerA) == SignOfIntoid (IntegerB));
- FreeIntoid (RecycleMe);
- if (ComparisonResult)
- return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
- else /* Have different signs. */
- return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
- }
-
- /* Handle future special codes. Already taken care of not-a-number
- and infinities before here. */
-
- if (IntoidIsSpecialCode (IntegerA))
- {
- FreeIntoid (RecycleMe);
- return IntegerA;
- }
-
- if (IntoidIsSpecialCode (IntegerB))
- {
- FreeIntoid (RecycleMe);
- return IntegerB;
- }
-
- /* Check for numbers that fit in a long so we can do a simpler long/intrep
- division. Note that IntRep denominator and long numerator won't occur
- since that result would be zero if the IntRep is normalized. */
-
- if (IntoidIsSmallInt (IntegerB))
- return NormalizeIntoid (DivideIntRepByLong (IntegerA,
- IntoidToSmallInt (IntegerB), RecycleMe));
-
- /* Ok, have two IntReps. */
-
- return NormalizeIntoid (DivideIntRepByIntRep (IntegerA, IntegerB,
- RecycleMe));
- }
-
-
-
- /******************************************************************************
- * Called by the SAS/C library wrapper when the library is expunged to clean
- * up globally allocated things.
- */
-
- void LIBFUNC __UserLibCleanup (REGA6 struct Library *LibraryBasePntr)
- {
- if (CurrentCatalog != NULL)
- {
- CloseCatalog (CurrentCatalog);
- CurrentCatalog = NULL;
- }
-
- if (CurrentLocale != NULL)
- {
- CloseLocale (CurrentLocale);
- CurrentLocale = NULL;
- }
-
- if (LocaleBase != NULL)
- {
-
- CloseLibrary (LocaleBase);
- LocaleBase = NULL;
- }
-
- if (UtilityBase != NULL)
- {
- CloseLibrary (UtilityBase);
- UtilityBase = NULL;
- }
-
- if (IntuitionBase != NULL)
- {
- CloseLibrary ((struct Library *) IntuitionBase);
- IntuitionBase = NULL;
- }
-
- if (SysBase != NULL)
- {
- CloseLibrary ((struct Library *) SysBase);
- SysBase = NULL; /* Do this last, CloseLibrary uses SysBase! */
- }
- }
-
-
-
- /******************************************************************************
- * Library initialisation code called by the SAS/C library wrapper. Open
- * other libraries we need, do one time initialisation, returns zero if
- * successful.
- */
-
- long LIBFUNC __UserLibInit (REGA6 struct Library *LibraryBasePntr)
- {
- while (TRUE)
- {
- /* Open our copy of Execbase. Of course, OpenLibrary needs SysBase
- defined before it is open, so just use the value from the magic
- location 4 in memory for this one call. Needed for memory allocation
- functions, opening libraries, etc. */
-
- SysBase = (struct ExecBase *)*(struct Library **)4;
- SysBase = (struct ExecBase *) OpenLibrary ((UBYTE *) "exec.library", 0);
- if (SysBase == NULL)
- break;
-
- /* Open intuition.library (any version, so it works under AmigaDOS 1.3
- too), just in case we need to display error messages. */
-
- IntuitionBase = (struct IntuitionBase *)
- OpenLibrary ((UBYTE *) "intuition.library", 0);
- if (IntuitionBase == NULL)
- break;
-
- /* Need the utility library for international string comparison
- functions and 32 bit multiply and divide subroutines. */
-
- UtilityBase = OpenLibrary ((STRPTR) UTILITYNAME, 37);
- if (UtilityBase == NULL)
- {
- DisplayErrorMessage ("Need " UTILITYNAME " version 37.");
- break;
- }
-
- /* Open the locale library for international string support. It's
- optional so a NULL LocaleBase won't stop the program. */
-
- LocaleBase = OpenLibrary ((STRPTR) "locale.library", 0);
-
- if (LocaleBase != NULL)
- CurrentLocale = OpenLocale (NULL /* The default country & language */);
-
- if (LocaleBase != NULL)
- CurrentCatalog = OpenCatalog (CurrentLocale /* Can be NULL */,
- (STRPTR) "Intoids.catalog", OC_BuiltInLanguage, "english", TAG_DONE);
-
- return 0; /* Success! */
- }
-
- return 1; /* Failure. */
- }
-